Author: rhauch
Date: 2008-08-18 17:38:58 -0400 (Mon, 18 Aug 2008)
New Revision: 440
Added:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FiveContributionMergePlanTest.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FourContributionMergePlanTest.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/MergePlanTest.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlanTest.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/OneContributionMergePlanTest.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/ThreeContributionMergePlanTest.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/TwoContributionMergePlanTest.java
trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties
Removed:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/BasicFederatedNodeTest.java
Modified:
trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/BasicCachePolicy.java
trunk/dna-spi/src/test/java/org/jboss/dna/spi/connector/SimpleRepository.java
trunk/dna-spi/src/test/java/org/jboss/dna/spi/connector/SimpleRepositorySource.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/Projection.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FiveContributionMergePlan.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FourContributionMergePlan.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlan.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/OneContributionMergePlan.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/StandardMergeStrategy.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/ThreeContributionMergePlan.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/TwoContributionMergePlan.java
trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionTest.java
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutorTest.java
trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheSourceTest.java
Log:
DNA-188 - Complete the federating command executor
http://jira.jboss.com/jira/browse/DNA-188
Changed the signature of the BasicCachePolicy, which affected several tests and test
classes. Also added quite a few more unit tests to the federation connector code.
Modified:
trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java
===================================================================
---
trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/dna-repository/src/test/java/org/jboss/dna/repository/RepositoryServiceTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -96,7 +96,7 @@
configSourceName = "configSource";
Projection.Rule configProjectionRule = new Projection.PathRule(pathInRepository,
pathInSource);
configProjection = new Projection(configSourceName, configProjectionRule);
- configRepository = new SimpleRepository("Configuration Repository");
+ configRepository = SimpleRepository.get("Configuration Repository");
configRepositorySource = new SimpleRepositorySource();
configRepositorySource.setRepositoryName(configRepository.getRepositoryName());
configRepositorySource.setName(configSourceName);
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/BasicCachePolicy.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/BasicCachePolicy.java 2008-08-18
18:45:57 UTC (rev 439)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/cache/BasicCachePolicy.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -21,19 +21,24 @@
*/
package org.jboss.dna.spi.cache;
+import java.util.concurrent.TimeUnit;
+import org.jboss.dna.common.util.ArgCheck;
+
/**
* @author Randall Hauch
*/
public class BasicCachePolicy implements CachePolicy {
private static final long serialVersionUID = 1L;
- private long timeToLive;
+ private long timeToLiveInMillis = 0L;
public BasicCachePolicy() {
}
- public BasicCachePolicy( long timeToCache ) {
- this.timeToLive = timeToCache;
+ public BasicCachePolicy( long timeToCache,
+ TimeUnit unit ) {
+ ArgCheck.isNotNull(unit, "unit");
+ this.timeToLiveInMillis = TimeUnit.MILLISECONDS.convert(timeToCache, unit);
}
/**
@@ -42,18 +47,22 @@
* @see org.jboss.dna.spi.cache.CachePolicy#getTimeToLive()
*/
public long getTimeToLive() {
- return this.timeToLive;
+ return this.timeToLiveInMillis;
}
/**
+ * Set the time for values and information to live in the cache.
+ *
* @param timeToLive Sets timeToLive to the specified value.
+ * @param unit the unit in which the time to live value is defined
*/
- public void setTimeToLive( long timeToLive ) {
- this.timeToLive = timeToLive;
+ public void setTimeToLive( long timeToLive,
+ TimeUnit unit ) {
+ this.timeToLiveInMillis = TimeUnit.NANOSECONDS.convert(timeToLive, unit);
}
public boolean isEmpty() {
- return this.timeToLive == 0;
+ return this.timeToLiveInMillis == 0;
}
public CachePolicy getUnmodifiable() {
@@ -83,7 +92,7 @@
*/
@Override
public String toString() {
- return "{ TTL=" + this.timeToLive + " }";
+ return "{ TTL=" + this.timeToLiveInMillis + " ms }";
}
}
Modified: trunk/dna-spi/src/test/java/org/jboss/dna/spi/connector/SimpleRepository.java
===================================================================
---
trunk/dna-spi/src/test/java/org/jboss/dna/spi/connector/SimpleRepository.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/dna-spi/src/test/java/org/jboss/dna/spi/connector/SimpleRepository.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -37,6 +37,7 @@
import org.jboss.dna.spi.graph.PathFactory;
import org.jboss.dna.spi.graph.Property;
import org.jboss.dna.spi.graph.PropertyFactory;
+import org.jboss.dna.spi.graph.impl.BasicPath;
/**
* A very simple repository that maintains properties for nodes identified by a path, and
computes the children based upon the set
@@ -57,7 +58,9 @@
private static final ConcurrentMap<String, SimpleRepository> repositoriesByName
= new ConcurrentHashMap<String, SimpleRepository>();
public static SimpleRepository get( String name ) {
- return repositoriesByName.get(name);
+ SimpleRepository newRepository = new SimpleRepository(name);
+ SimpleRepository repository = repositoriesByName.putIfAbsent(name,
newRepository);
+ return repository != null ? repository : newRepository;
}
public static void shutdownAll() {
@@ -73,9 +76,11 @@
public SimpleRepository( String repositoryName ) {
this.repositoryName = repositoryName;
- if (repositoriesByName.putIfAbsent(repositoryName, this) != null) {
- throw new IllegalArgumentException("Repository \"" +
repositoryName + "\" already exists and may not be recreated");
- }
+ // if (repositoriesByName.putIfAbsent(repositoryName, this) != null) {
+ // throw new IllegalArgumentException("Repository \"" +
repositoryName + "\" already exists and may not be recreated");
+ // }
+ // Create a root node ...
+ data.putIfAbsent(BasicPath.ROOT, new HashMap<Name, Property>());
}
/**
Modified:
trunk/dna-spi/src/test/java/org/jboss/dna/spi/connector/SimpleRepositorySource.java
===================================================================
---
trunk/dna-spi/src/test/java/org/jboss/dna/spi/connector/SimpleRepositorySource.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/dna-spi/src/test/java/org/jboss/dna/spi/connector/SimpleRepositorySource.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -59,6 +59,7 @@
private String repositoryName;
private String name;
private final AtomicInteger retryLimit = new AtomicInteger(DEFAULT_RETRY_LIMIT);
+ private CachePolicy defaultCachePolicy;
public SimpleRepositorySource() {
super();
@@ -113,6 +114,20 @@
}
/**
+ * @return defaultCachePolicy
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ return defaultCachePolicy;
+ }
+
+ /**
+ * @param defaultCachePolicy Sets defaultCachePolicy to the specified value.
+ */
+ public void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
+ this.defaultCachePolicy = defaultCachePolicy;
+ }
+
+ /**
* {@inheritDoc}
*
* @see javax.naming.Referenceable#getReference()
@@ -174,21 +189,25 @@
*/
public RepositoryConnection getConnection() throws RepositorySourceException {
String reposName = this.getRepositoryName();
+ if (reposName == null) throw new RepositorySourceException("Invalid
repository source: missing repository name");
SimpleRepository repository = SimpleRepository.get(reposName);
if (repository == null) {
throw new RepositorySourceException(this.getName(), "Unable to find
repository \"" + reposName + "\"");
}
- return new Connection(repository);
+ return new Connection(repository, this.getDefaultCachePolicy());
}
protected class Connection implements RepositoryConnection {
private RepositorySourceListener listener;
private final SimpleRepository repository;
+ private final CachePolicy defaultCachePolicy;
- protected Connection( SimpleRepository repository ) {
+ protected Connection( SimpleRepository repository,
+ CachePolicy defaultCachePolicy ) {
assert repository != null;
this.repository = repository;
+ this.defaultCachePolicy = defaultCachePolicy;
}
/**
@@ -225,7 +244,7 @@
* @see org.jboss.dna.spi.connector.RepositoryConnection#getDefaultCachePolicy()
*/
public CachePolicy getDefaultCachePolicy() {
- return null;
+ return defaultCachePolicy;
}
/**
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -28,6 +28,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.naming.Context;
import javax.naming.InitialContext;
@@ -823,7 +824,7 @@
BasicCachePolicy cachePolicy = new BasicCachePolicy();
Property timeToLiveProperty =
getRepository.getPropertiesByName().get(nameFactory.create(CACHE_POLICY_TIME_TO_LIVE_CONFIG_PROPERTY_NAME));
if (timeToLiveProperty != null && !timeToLiveProperty.isEmpty()) {
-
cachePolicy.setTimeToLive(longFactory.create(timeToLiveProperty.getValues().next()));
+
cachePolicy.setTimeToLive(longFactory.create(timeToLiveProperty.getValues().next()),
TimeUnit.MILLISECONDS);
}
CachePolicy defaultCachePolicy = cachePolicy.isEmpty() ? null :
cachePolicy.getUnmodifiable();
return new FederatedRepositoryConfig(repositoryName, cacheProjection,
sourceProjections, defaultCachePolicy);
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -32,6 +32,8 @@
public static I18n requiredNodeDoesNotExistRelativeToNode;
public static I18n propertyIsRequired;
+ public static I18n nodeDoesNotExistAtPath;
+ public static I18n errorRemovingNodeFromCache;
public static I18n interruptedWhileUsingFederationConfigurationRepository;
public static I18n unableToFindFederatedRepositoryInJndi;
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/Projection.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/Projection.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/Projection.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -172,7 +172,7 @@
* Pattern that identifies the form:
*
* <pre>
- * repository_path [=> source_path [$ exception ]*]?
+ * repository_path => source_path [$ exception ]*
* </pre>
*
* where the following groups are captured on the first call to {@link
Matcher#find()}:
@@ -212,6 +212,10 @@
if (!matcher.find()) return null;
String reposPathStr = matcher.group(1);
String sourcePathStr = matcher.group(2);
+ if (reposPathStr == null || sourcePathStr == null) return null;
+ reposPathStr = reposPathStr.trim();
+ sourcePathStr = sourcePathStr.trim();
+ if (reposPathStr.length() == 0 || sourcePathStr.length() == 0) return null;
PathFactory pathFactory = context.getValueFactories().getPathFactory();
Path repositoryPath = pathFactory.create(reposPathStr);
Path sourcePath = pathFactory.create(sourcePathStr);
@@ -315,6 +319,21 @@
}
/**
+ * Get the paths in the repository that serve as top-level nodes exposed by this
projection.
+ *
+ * @param factory the path factory that can be used to create new paths; may not be
null
+ * @return the set of top-level paths; never null
+ */
+ public Set<Path> getTopLevelPathsInRepository( PathFactory factory ) {
+ ArgCheck.isNotNull(factory, "factory");
+ Set<Path> paths = new HashSet<Path>();
+ for (Rule rule : getRules()) {
+ paths.addAll(rule.getTopLevelPathsInRepository(factory));
+ }
+ return paths;
+ }
+
+ /**
* Determine whether this project is a simple projection that only involves for any
one repository path no more than a single
* source path.
*
@@ -415,7 +434,7 @@
}
/**
- * A rule used within a project do define how content within a source is project into
the federated repository. This mapping
+ * A rule used within a project do define how content within a source is projected
into the federated repository. This mapping
* is bi-directional, meaning it's possible to determine
* <ul>
* <li>the path in repository given a path in source; and</li>
@@ -426,7 +445,16 @@
*/
@Immutable
public static abstract class Rule implements Comparable<Rule> {
+
/**
+ * Get the paths in the repository that serve as top-level nodes exposed by this
rule.
+ *
+ * @param factory the path factory that can be used to create new paths; may not
be null
+ * @return the set of top-level paths; never null
+ */
+ public abstract Set<Path> getTopLevelPathsInRepository( PathFactory factory
);
+
+ /**
* Get the path in source that is projected from the supplied repository path, or
null if the supplied repository path is
* not projected into the source.
*
@@ -585,6 +613,16 @@
/**
* {@inheritDoc}
+ *
+ * @see
org.jboss.dna.connector.federation.Projection.Rule#getTopLevelPathsInRepository(org.jboss.dna.spi.graph.PathFactory)
+ */
+ @Override
+ public Set<Path> getTopLevelPathsInRepository( PathFactory factory ) {
+ return Collections.singleton(getPathInRepository());
+ }
+
+ /**
+ * {@inheritDoc}
* <p>
* This method considers a path that is at or below the rule's {@link
#getPathInSource() source path} to be included,
* except if there are {@link #getExceptionsToRule() exceptions} that explicitly
disallow the path.
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -26,11 +26,13 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.spi.graph.DateTime;
import org.jboss.dna.spi.graph.Name;
import org.jboss.dna.spi.graph.Path;
import org.jboss.dna.spi.graph.Property;
import org.jboss.dna.spi.graph.Path.Segment;
+import org.jboss.dna.spi.graph.impl.JodaDateTime;
/**
* The contribution of a source to the information for a single federated node. Users of
this interface should treat contributions
@@ -287,6 +289,15 @@
}
/**
+ * Return whether this contribution is an empty contribution.
+ *
+ * @return true if this contribution is empty, or false otherwise
+ */
+ public boolean isEmpty() {
+ return false;
+ }
+
+ /**
* {@inheritDoc}
* <p>
* This implementation returns the hash code of the {@link #getSourceName() source
name}, and is compatible with the
@@ -300,6 +311,51 @@
/**
* {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("Contribution from \"");
+ sb.append(getSourceName());
+ if (isExpired(new JodaDateTime().toUtcTimeZone())) {
+ sb.append("\": expired ");
+ } else {
+ sb.append("\": expires ");
+ }
+ sb.append(getExpirationTimeInUtc().getString());
+ if (getPropertyCount() != 0) {
+ sb.append(" { ");
+ boolean first = true;
+ Iterator<Property> propIter = getProperties();
+ while (propIter.hasNext()) {
+ if (!first) sb.append(", ");
+ else first = false;
+ Property property = propIter.next();
+ sb.append(property.getName());
+ sb.append('=');
+ sb.append(StringUtil.readableString(property.getValuesAsArray()));
+ }
+ sb.append(" }");
+ }
+ if (getChildrenCount() != 0) {
+ sb.append("< ");
+ boolean first = true;
+ Iterator<Segment> childIter = getChildren();
+ while (childIter.hasNext()) {
+ if (!first) sb.append(", ");
+ else first = false;
+ Segment child = childIter.next();
+ sb.append(child);
+ }
+ sb.append(" >");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * {@inheritDoc}
* <p>
* This implementation only compares the {@link #getSourceName() source name}.
* </p>
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -68,8 +68,18 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.connector.federation.contribution.Contribution#isEmpty()
*/
@Override
+ public boolean isEmpty() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public boolean equals( Object obj ) {
if (obj == this) return true;
if (obj instanceof EmptyContribution) {
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -30,8 +30,11 @@
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.connector.federation.FederationI18n;
import org.jboss.dna.connector.federation.Projection;
import org.jboss.dna.connector.federation.contribution.Contribution;
import org.jboss.dna.connector.federation.merge.FederatedNode;
@@ -47,7 +50,6 @@
import org.jboss.dna.spi.connector.RepositorySource;
import org.jboss.dna.spi.connector.RepositorySourceException;
import org.jboss.dna.spi.graph.DateTime;
-import org.jboss.dna.spi.graph.DateTimeFactory;
import org.jboss.dna.spi.graph.Name;
import org.jboss.dna.spi.graph.Path;
import org.jboss.dna.spi.graph.PathFactory;
@@ -61,7 +63,6 @@
import org.jboss.dna.spi.graph.commands.NodeConflictBehavior;
import org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor;
import org.jboss.dna.spi.graph.commands.impl.BasicCreateNodeCommand;
-import org.jboss.dna.spi.graph.commands.impl.BasicGetChildrenCommand;
import org.jboss.dna.spi.graph.commands.impl.BasicGetNodeCommand;
import org.jboss.dna.spi.graph.impl.BasicSingleValueProperty;
@@ -78,11 +79,12 @@
private final List<Projection> sourceProjections;
private final Set<String> sourceNames;
private final RepositoryConnectionFactory connectionFactory;
- private final MergeStrategy mergingStrategy;
+ private MergeStrategy mergingStrategy;
/** The set of all connections, including the cache connection */
private final Map<String, RepositoryConnection> connectionsBySourceName;
/** A direct reference to the cache connection */
private RepositoryConnection cacheConnection;
+ private Logger logger;
/**
* Create a command executor that federates (merges) the information from multiple
sources described by the source
@@ -139,14 +141,52 @@
for (Projection projection : this.sourceProjections) {
this.sourceNames.add(projection.getSourceName());
}
- if (this.sourceProjections.size() == 1 &&
this.sourceProjections.get(0).isSimple()) {
- this.mergingStrategy = new OneContributionMergeStrategy();
+ setLogger(null);
+ setMergingStrategy(null);
+ }
+
+ /**
+ * @param logger Sets logger to the specified value.
+ */
+ public void setLogger( Logger logger ) {
+ this.logger = logger != null ? logger : Logger.getLogger(getClass());
+ }
+
+ /**
+ * @param mergingStrategy Sets mergingStrategy to the specified value.
+ */
+ public void setMergingStrategy( MergeStrategy mergingStrategy ) {
+ if (mergingStrategy != null) {
+ this.mergingStrategy = mergingStrategy;
} else {
- this.mergingStrategy = new StandardMergeStrategy(DnaLexicon.UUID);
+ if (this.sourceProjections.size() == 1 &&
this.sourceProjections.get(0).isSimple()) {
+ this.mergingStrategy = new OneContributionMergeStrategy();
+ } else {
+ this.mergingStrategy = new StandardMergeStrategy(DnaLexicon.UUID);
+ }
}
+ assert this.mergingStrategy != null;
}
/**
+ * Get an unmodifiable list of the immutable source projections.
+ *
+ * @return the set of projections used as sources; never null
+ */
+ public List<Projection> getSourceProjections() {
+ return Collections.unmodifiableList(sourceProjections);
+ }
+
+ /**
+ * Get the projection defining the cache.
+ *
+ * @return the cache projection
+ */
+ public Projection getCacheProjection() {
+ return cacheProjection;
+ }
+
+ /**
* {@inheritDoc}
*
* @see org.jboss.dna.spi.graph.commands.executor.AbstractCommandExecutor#close()
@@ -187,6 +227,10 @@
return connection;
}
+ protected Set<String> getOpenConnections() {
+ return connectionsBySourceName.keySet();
+ }
+
/**
* {@inheritDoc}
* <p>
@@ -199,6 +243,7 @@
@Override
public void execute( GetNodeCommand command ) throws RepositorySourceException,
InterruptedException {
BasicGetNodeCommand nodeInfo = getNode(command.getPath());
+ if (nodeInfo.hasError()) return;
for (Property property : nodeInfo.getProperties()) {
command.setProperty(property);
}
@@ -215,6 +260,7 @@
@Override
public void execute( GetPropertiesCommand command ) throws RepositorySourceException,
InterruptedException {
BasicGetNodeCommand nodeInfo = getNode(command.getPath());
+ if (nodeInfo.hasError()) return;
for (Property property : nodeInfo.getProperties()) {
command.setProperty(property);
}
@@ -228,6 +274,7 @@
@Override
public void execute( GetChildrenCommand command ) throws RepositorySourceException,
InterruptedException {
BasicGetNodeCommand nodeInfo = getNode(command.getPath());
+ if (nodeInfo.hasError()) return;
for (Segment child : nodeInfo.getChildren()) {
command.addChild(child, nodeInfo.getChildIdentityProperties(child));
}
@@ -247,106 +294,191 @@
RepositoryConnection cacheConnection = getConnectionToCache();
BasicGetNodeCommand fromCache = new BasicGetNodeCommand(path);
cacheConnection.execute(context, fromCache);
+
+ // Look at the cache results from the cache for problems, or if found a plan in
the cache look
+ // at the contributions. We'll be putting together the set of source names
for which we need to
+ // get the contributions.
+ Set<String> sourceNames = null;
+ List<Contribution> contributions = new LinkedList<Contribution>();
+
if (fromCache.hasError()) {
- if (fromCache.getError() instanceof PathNotFoundException) {
- // The path was not found in the cache, so since we don't know
whether the ancestors are federated
- // from multiple source nodes, we need to populate the cache starting
with the lowest ancestor
- // that already exists in the cache.
- PathNotFoundException notFound =
(PathNotFoundException)fromCache.getError();
- Path lowestExistingAncestor = notFound.getLowestAncestorThatDoesExist();
- Path ancestor = path.getAncestor();
+ Throwable error = fromCache.getError();
+ if (!(error instanceof PathNotFoundException)) return fromCache;
- if (!ancestor.equals(lowestExistingAncestor)) {
- // Create the commands that load the children (not properties) of the
existing ancestor,
- // then the children (not properties) of the child next on the
desired path, etc.,
- // down to (but excluding) the desired path.
- LinkedList<BasicGetChildrenCommand> loadChildrenCommands = new
LinkedList<BasicGetChildrenCommand>();
- Path pathToLoad = path.getAncestor();
- while (!pathToLoad.equals(lowestExistingAncestor)) {
- BasicGetChildrenCommand command = new
BasicGetChildrenCommand(pathToLoad);
- loadChildrenCommands.addFirst(command);
- pathToLoad = pathToLoad.getAncestor();
+ // The path was not found in the cache, so since we don't know whether
the ancestors are federated
+ // from multiple source nodes, we need to populate the cache starting with
the lowest ancestor
+ // that already exists in the cache.
+ PathNotFoundException notFound =
(PathNotFoundException)fromCache.getError();
+ Path lowestExistingAncestor = notFound.getLowestAncestorThatDoesExist();
+ Path ancestor = path.getAncestor();
+
+ if (!ancestor.equals(lowestExistingAncestor)) {
+ // Load the nodes along the path below the existing ancestor, down to
(but excluding) the desired path
+ Path pathToLoad = path.getAncestor();
+ while (!pathToLoad.equals(lowestExistingAncestor)) {
+ loadContributionsFromSources(pathToLoad, null, contributions); //
sourceNames may be null or empty
+ FederatedNode mergedNode = createFederatedNode(pathToLoad,
contributions, true);
+ if (mergedNode == null) {
+ // No source had a contribution ...
+ I18n msg = FederationI18n.nodeDoesNotExistAtPath;
+ fromCache.setError(new PathNotFoundException(path, ancestor,
msg.text(path, ancestor)));
+ return fromCache;
}
- // Now execute these commands (one-by-one is fine, since this is an
executor) ...
- for (BasicGetChildrenCommand command : loadChildrenCommands) {
- execute(command);
+ contributions.clear();
+ // Move to the next child along the path ...
+ pathToLoad = pathToLoad.getAncestor();
+ }
+ }
+ // At this point, all ancestors exist ...
+ } else {
+ // There is no error, so look for the merge plan ...
+ MergePlan mergePlan = getMergePlan(fromCache);
+ if (mergePlan != null) {
+ // We found the merge plan, so check whether it's still valid ...
+ final DateTime now = getCurrentTimeInUtc();
+ if (mergePlan.isExpired(now)) {
+ // It is still valid, so check whether any contribution is from a
non-existant projection ...
+ for (Contribution contribution : mergePlan) {
+ if (!this.sourceNames.contains(contribution.getSourceName())) {
+ // TODO: Record that the cached contribution is from a source
that is no longer in this repository
+ }
}
+ return fromCache;
}
- // Load the node from the sources ...
- FederatedNode mergedNode = loadFromSources(path);
+ // At least one of the contributions is expired, so go through the
contributions and place
+ // the valid contributions in the 'contributions' list; any
expired contribution
+ // needs to be loaded by adding the name to the 'sourceNames'
+ if (mergePlan.getContributionCount() > 0) {
+ sourceNames = new HashSet<String>(sourceNames);
+ for (Contribution contribution : mergePlan) {
+ if (!contribution.isExpired(now)) {
+ sourceNames.remove(contribution.getSourceName());
+ contributions.add(contribution);
+ }
+ }
+ }
+ }
+ }
- // Place the results into the cache ...
- updateCache(mergedNode);
+ // Get the contributions from the sources given their names ...
+ loadContributionsFromSources(path, sourceNames, contributions); // sourceNames
may be null or empty
+ FederatedNode mergedNode = createFederatedNode(path, contributions, true);
+ if (mergedNode == null) {
+ // No source had a contribution ...
+ Path ancestor = path.getAncestor();
+ I18n msg = FederationI18n.nodeDoesNotExistAtPath;
+ fromCache.setError(new PathNotFoundException(path, ancestor, msg.text(path,
ancestor)));
+ return fromCache;
+ }
+ return mergedNode;
+ }
- // Return the results ...
- return mergedNode;
+ protected FederatedNode createFederatedNode( Path path,
+ List<Contribution> contributions,
+ boolean updateCache ) throws
RepositorySourceException, InterruptedException {
+
+ // If there are no contributions from any source ...
+ boolean foundNonEmptyContribution = false;
+ for (Contribution contribution : contributions) {
+ if (!contribution.isEmpty()) {
+ foundNonEmptyContribution = true;
+ break;
}
- return fromCache; // with an error
}
+ if (foundNonEmptyContribution) return null;
+ if (logger.isTraceEnabled()) {
+ logger.trace("Loaded {0} from sources, resulting in these
contributions:", path);
+ int i = 0;
+ for (Contribution contribution : contributions) {
+ logger.trace(" {0} {1}", ++i, contribution);
+ }
+ }
- // The cache had the node information, so look for the merge plan ...
- MergePlan mergePlan = getMergePlan(fromCache);
- assert mergePlan != null;
- if (!isCurrent(path, mergePlan)) {
- // Some of the merge plan is out of date, so we need to read the information
from those regions that are expired ...
- // MergePlan newMergePlan = new BasicMergePlan();
- // for (Projection projection : sourceProjections) {
- // // Does this region apply to the path ...
- // if (projection.appliesTo(path)) {
- // // Get any existing contribution ...
- // Contribution contribution =
mergePlan.getContributionFrom(region.getSourceName());
- // if (contribution == null || contribution.isExpired(getCurrentTimeInUtc()))
{
- // contribution = getContribution(contribution.getSourceName(), path);
- // }
- // newMergePlan.addContribution(contribution);
- // }
- // }
- // for ( Contribution contribution : mergePlan.getContributions() ) {
- // // Is the contribution still represented by a region?
- //
- // if ( contribution.isExpired(getCurrentTimeInUtc())) {
- // contribution = getContribution(contribution.getSourceName(),path);
- // }
- // newMergePlan.addContribution(contribution);
- // }
-
- // What about other (new) regions?
+ // Merge the results into a single set of results ...
+ FederatedNode mergedNode = new FederatedNode(path, UUID.randomUUID());
+ ExecutionContext context = getExecutionContext();
+ mergingStrategy.merge(mergedNode, contributions, context);
+ if (mergedNode.getCachePolicy() == null) {
+ mergedNode.setCachePolicy(defaultCachePolicy);
}
-
- return fromCache;
+ if (updateCache) {
+ // Place the results into the cache ...
+ updateCache(mergedNode);
+ }
+ // And return the results ...
+ return mergedNode;
}
/**
+ * Load the node at the supplied path from the sources with the supplied name,
returning the information. This method always
+ * obtains the information from the sources and does not use or update the cache.
+ *
* @param path the path of the node that is to be loaded
- * @return the federated node containing information loaded from the sources
+ * @param sourceNames the names of the sources from which contributions are to be
loaded; may be empty or null if all
+ * contributions from all sources are to be loaded
+ * @param contributions the list into which the contributions are to be placed
* @throws InterruptedException
* @throws RepositorySourceException
*/
- protected FederatedNode loadFromSources( Path path ) throws
RepositorySourceException, InterruptedException {
+ protected void loadContributionsFromSources( Path path,
+ Set<String> sourceNames,
+ List<Contribution> contributions
)
+ throws RepositorySourceException, InterruptedException {
// At this point, there is no merge plan, so read information from the sources
...
ExecutionContext context = getExecutionContext();
PathFactory pathFactory = context.getValueFactories().getPathFactory();
- DateTimeFactory timeFactory = context.getValueFactories().getDateFactory();
- List<Contribution> contributions = new LinkedList<Contribution>();
for (Projection projection : this.sourceProjections) {
final String source = projection.getSourceName();
+ if (sourceNames != null && !sourceNames.contains(source)) continue;
final RepositoryConnection sourceConnection = getConnection(projection);
+ if (sourceConnection == null) continue; // No source exists by this name
try {
// Get the cached information ...
CachePolicy cachePolicy = sourceConnection.getDefaultCachePolicy();
if (cachePolicy == null) cachePolicy = this.defaultCachePolicy;
DateTime expirationTime = null;
if (cachePolicy != null) {
- expirationTime = timeFactory.create(getCurrentTimeInUtc(),
cachePolicy.getTimeToLive());
+ expirationTime =
getCurrentTimeInUtc().plus(cachePolicy.getTimeToLive(), TimeUnit.MILLISECONDS);
}
// Get the paths-in-source where we should fetch node contributions ...
Set<Path> pathsInSource = projection.getPathsInSource(path,
pathFactory);
if (pathsInSource.isEmpty()) {
- // The source has no contributions ...
- contributions.add(Contribution.create(source, expirationTime));
+ // The source has no contributions, but see whether the project
exists BELOW this path.
+ // We do this by getting the top-level repository paths of the
projection, and then
+ // use those to figure out the children of the nodes.
+ Contribution contribution = null;
+ Set<Path> topLevelPaths =
projection.getTopLevelPathsInRepository(pathFactory);
+ switch (topLevelPaths.size()) {
+ case 0:
+ break;
+ case 1: {
+ Path topLevelPath = topLevelPaths.iterator().next();
+ if (path.isAncestorOf(topLevelPath)) {
+ assert topLevelPath.size() > path.size();
+ Path.Segment child =
topLevelPath.getSegment(path.size());
+ contribution = Contribution.create(source, path,
expirationTime, null, child);
+ }
+ break;
+ }
+ default: {
+ Set<Path.Segment> children = new
HashSet<Path.Segment>();
+ for (Path topLevelPath : topLevelPaths) {
+ if (path.isAncestorOf(topLevelPath)) {
+ assert topLevelPath.size() > path.size();
+ Path.Segment child =
topLevelPath.getSegment(path.size());
+ children.add(child);
+ }
+ }
+ if (children.size() > 0) {
+ contribution = Contribution.create(source, path,
expirationTime, null, children);
+ }
+ }
+ }
+ if (contribution == null) contribution = Contribution.create(source,
expirationTime);
+ contributions.add(contribution);
} else {
- // There is at least one contribution ...
+ // There is at least one (real) contribution ...
// Get the contributions ...
final int numPaths = pathsInSource.size();
@@ -357,8 +489,8 @@
if (!fromSource.hasError()) {
Collection<Property> properties =
fromSource.getProperties();
Collection<Segment> children =
fromSource.getChildren();
- DateTime expTime = fromSource.getCachePolicy() == null ?
expirationTime : timeFactory.create(getCurrentTimeInUtc(),
-
fromSource.getCachePolicy().getTimeToLive());
+ DateTime expTime = fromSource.getCachePolicy() == null ?
expirationTime : getCurrentTimeInUtc().plus(fromSource.getCachePolicy().getTimeToLive(),
+
TimeUnit.MILLISECONDS);
Contribution contribution = Contribution.create(source,
pathInSource, expTime, properties, children);
contributions.add(contribution);
}
@@ -373,8 +505,8 @@
if (fromSource.hasError()) continue;
Collection<Property> properties =
fromSource.getProperties();
Collection<Segment> children =
fromSource.getChildren();
- DateTime expTime = fromSource.getCachePolicy() == null ?
expirationTime : timeFactory.create(getCurrentTimeInUtc(),
-
fromSource.getCachePolicy().getTimeToLive());
+ DateTime expTime = fromSource.getCachePolicy() == null ?
expirationTime : getCurrentTimeInUtc().plus(fromSource.getCachePolicy().getTimeToLive(),
+
TimeUnit.MILLISECONDS);
Contribution contribution = Contribution.create(source,
fromSource.getPath(),
expTime,
@@ -388,15 +520,140 @@
sourceConnection.close();
}
}
- // Merge the results into a single set of results ...
- FederatedNode mergedNode = new FederatedNode(path, UUID.randomUUID());
- mergingStrategy.merge(mergedNode, contributions, context);
- if (mergedNode.getCachePolicy() == null) {
- mergedNode.setCachePolicy(defaultCachePolicy);
- }
- return mergedNode;
}
+ // /**
+ // * Load the node at the supplied path, returning the information. This method
always obtains the information from the
+ // sources
+ // * and does not use or update the cache.
+ // *
+ // * @param path the path of the node that is to be loaded
+ // * @return the federated node containing information loaded from the sources, or
null if none of the sources had a
+ // * contribution
+ // * @throws InterruptedException
+ // * @throws RepositorySourceException
+ // */
+ // protected FederatedNode loadFromSources( Path path ) throws
RepositorySourceException, InterruptedException {
+ // // At this point, there is no merge plan, so read information from the sources
...
+ // ExecutionContext context = getExecutionContext();
+ // PathFactory pathFactory = context.getValueFactories().getPathFactory();
+ // DateTimeFactory timeFactory = context.getValueFactories().getDateFactory();
+ // List<Contribution> contributions = new LinkedList<Contribution>();
+ // boolean foundContribution = false;
+ // for (Projection projection : this.sourceProjections) {
+ // final String source = projection.getSourceName();
+ // final RepositoryConnection sourceConnection = getConnection(projection);
+ // if (sourceConnection == null) continue; // No source exists by this name
+ // try {
+ // // Get the cached information ...
+ // CachePolicy cachePolicy = sourceConnection.getDefaultCachePolicy();
+ // if (cachePolicy == null) cachePolicy = this.defaultCachePolicy;
+ // DateTime expirationTime = null;
+ // if (cachePolicy != null) {
+ // expirationTime = getCurrentTimeInUtc().plus(cachePolicy.getTimeToLive(),
TimeUnit.MILLISECONDS);
+ // }
+ // // Get the paths-in-source where we should fetch node contributions ...
+ // Set<Path> pathsInSource = projection.getPathsInSource(path, pathFactory);
+ // if (pathsInSource.isEmpty()) {
+ // // The source has no contributions, but see whether the project exists BELOW this
path.
+ // // We do this by getting the top-level repository paths of the projection, and
then
+ // // use those to figure out the children of the nodes.
+ // Contribution contribution = null;
+ // Set<Path> topLevelPaths =
projection.getTopLevelPathsInRepository(pathFactory);
+ // switch (topLevelPaths.size()) {
+ // case 0:
+ // break;
+ // case 1: {
+ // Path topLevelPath = topLevelPaths.iterator().next();
+ // if (path.isAncestorOf(topLevelPath)) {
+ // assert topLevelPath.size() > path.size();
+ // Path.Segment child = topLevelPath.getSegment(path.size());
+ // contribution = Contribution.create(source, path, expirationTime, null, child);
+ // foundContribution = true;
+ // }
+ // break;
+ // }
+ // default: {
+ // Set<Path.Segment> children = new HashSet<Path.Segment>();
+ // for (Path topLevelPath : topLevelPaths) {
+ // if (path.isAncestorOf(topLevelPath)) {
+ // assert topLevelPath.size() > path.size();
+ // Path.Segment child = topLevelPath.getSegment(path.size());
+ // children.add(child);
+ // }
+ // }
+ // if (children.size() > 0) {
+ // contribution = Contribution.create(source, path, expirationTime, null, children);
+ // foundContribution = true;
+ // }
+ // }
+ // }
+ // if (contribution == null) contribution = Contribution.create(source,
expirationTime);
+ // contributions.add(contribution);
+ // } else {
+ // // There is at least one (real) contribution ...
+ //
+ // // Get the contributions ...
+ // final int numPaths = pathsInSource.size();
+ // if (numPaths == 1) {
+ // Path pathInSource = pathsInSource.iterator().next();
+ // BasicGetNodeCommand fromSource = new BasicGetNodeCommand(pathInSource);
+ // sourceConnection.execute(getExecutionContext(), fromSource);
+ // if (!fromSource.hasError()) {
+ // Collection<Property> properties = fromSource.getProperties();
+ // Collection<Segment> children = fromSource.getChildren();
+ // DateTime expTime = fromSource.getCachePolicy() == null ? expirationTime :
timeFactory.create(getCurrentTimeInUtc(),
+ // fromSource.getCachePolicy().getTimeToLive());
+ // Contribution contribution = Contribution.create(source, pathInSource, expTime,
properties, children);
+ // if (!contribution.isEmpty()) foundContribution = true;
+ // contributions.add(contribution);
+ // }
+ // } else {
+ // BasicGetNodeCommand[] fromSourceCommands = new BasicGetNodeCommand[numPaths];
+ // int i = 0;
+ // for (Path pathInSource : pathsInSource) {
+ // fromSourceCommands[i++] = new BasicGetNodeCommand(pathInSource);
+ // }
+ // sourceConnection.execute(context, fromSourceCommands);
+ // for (BasicGetNodeCommand fromSource : fromSourceCommands) {
+ // if (fromSource.hasError()) continue;
+ // Collection<Property> properties = fromSource.getProperties();
+ // Collection<Segment> children = fromSource.getChildren();
+ // DateTime expTime = fromSource.getCachePolicy() == null ? expirationTime :
timeFactory.create(getCurrentTimeInUtc(),
+ // fromSource.getCachePolicy().getTimeToLive());
+ // Contribution contribution = Contribution.create(source,
+ // fromSource.getPath(),
+ // expTime,
+ // properties,
+ // children);
+ // if (!contribution.isEmpty()) foundContribution = true;
+ // contributions.add(contribution);
+ // }
+ // }
+ // }
+ // } finally {
+ // sourceConnection.close();
+ // }
+ // }
+ // // If there are no contributions from any source ...
+ // if (!foundContribution) return null;
+ // if (logger.isTraceEnabled()) {
+ // logger.trace("Loaded {0} from sources, resulting in these
contributions:", path);
+ // int i = 0;
+ // for (Contribution contribution : contributions) {
+ // logger.trace(" {0} {1}", ++i, contribution);
+ // }
+ // }
+ //
+ // // Merge the results into a single set of results ...
+ // FederatedNode mergedNode = new FederatedNode(path, UUID.randomUUID());
+ // mergingStrategy.merge(mergedNode, contributions, context);
+ // if (mergedNode.getCachePolicy() == null) {
+ // mergedNode.setCachePolicy(defaultCachePolicy);
+ // }
+ // return mergedNode;
+ // }
+ //
protected MergePlan getMergePlan( BasicGetNodeCommand command ) {
Property mergePlanProperty =
command.getPropertiesByName().get(mergePlanPropertyName);
if (mergePlanProperty == null || mergePlanProperty.isEmpty()) {
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FiveContributionMergePlan.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FiveContributionMergePlan.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FiveContributionMergePlan.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -24,6 +24,7 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.connector.federation.contribution.Contribution;
/**
@@ -46,11 +47,11 @@
* @param contribution4 the fourth contribution for this merge plan
* @param contribution5 the fifth contribution for this merge plan
*/
- public FiveContributionMergePlan( Contribution contribution1,
- Contribution contribution2,
- Contribution contribution3,
- Contribution contribution4,
- Contribution contribution5 ) {
+ /*package*/FiveContributionMergePlan( Contribution contribution1,
+ Contribution contribution2,
+ Contribution contribution3,
+ Contribution contribution4,
+ Contribution contribution5 ) {
assert contribution1 != null;
assert contribution2 != null;
assert contribution3 != null;
@@ -61,6 +62,7 @@
this.contribution3 = contribution3;
this.contribution4 = contribution4;
this.contribution5 = contribution5;
+ assert checkEachContributionIsFromDistinctSource();
}
/**
@@ -95,7 +97,7 @@
*/
public Iterator<Contribution> iterator() {
return new Iterator<Contribution>() {
- private int next = 4;
+ private int next = 5;
public boolean hasNext() {
return next > 0;
@@ -147,4 +149,14 @@
return false;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.compute(contribution1, contribution2, contribution3,
contribution4, contribution5);
+ }
+
}
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FourContributionMergePlan.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FourContributionMergePlan.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FourContributionMergePlan.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -24,6 +24,7 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.connector.federation.contribution.Contribution;
/**
@@ -44,10 +45,10 @@
* @param contribution3 the third contribution for this merge plan
* @param contribution4 the fourth contribution for this merge plan
*/
- public FourContributionMergePlan( Contribution contribution1,
- Contribution contribution2,
- Contribution contribution3,
- Contribution contribution4 ) {
+ /*package*/FourContributionMergePlan( Contribution contribution1,
+ Contribution contribution2,
+ Contribution contribution3,
+ Contribution contribution4 ) {
assert contribution1 != null;
assert contribution2 != null;
assert contribution3 != null;
@@ -56,6 +57,7 @@
this.contribution2 = contribution2;
this.contribution3 = contribution3;
this.contribution4 = contribution4;
+ assert checkEachContributionIsFromDistinctSource();
}
/**
@@ -136,4 +138,14 @@
return false;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.compute(contribution1, contribution2, contribution3,
contribution4);
+ }
+
}
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MergePlan.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -24,11 +24,19 @@
import java.io.InvalidClassException;
import java.io.Serializable;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.StringUtil;
import org.jboss.dna.connector.federation.contribution.Contribution;
import org.jboss.dna.connector.federation.contribution.EmptyContribution;
import org.jboss.dna.spi.graph.DateTime;
@@ -54,6 +62,8 @@
public static MergePlan create( Contribution... contributions ) {
ArgCheck.isNotNull(contributions, "contributions");
switch (contributions.length) {
+ case 0:
+ throw new
IllegalArgumentException(CommonI18n.argumentMayNotBeEmpty.text("contributions"));
case 1:
return new OneContributionMergePlan(contributions[0]);
case 2:
@@ -74,6 +84,8 @@
ArgCheck.isNotNull(contributions, "contributions");
Iterator<Contribution> iter = contributions.iterator();
switch (contributions.size()) {
+ case 0:
+ throw new
IllegalArgumentException(CommonI18n.argumentMayNotBeEmpty.text("contributions"));
case 1:
return new OneContributionMergePlan(iter.next());
case 2:
@@ -91,10 +103,11 @@
public static MergePlan addContribution( MergePlan plan,
Contribution contribution ) {
+ ArgCheck.isNotNull(plan, "plan");
+ ArgCheck.isNotNull(contribution, "contribution");
if (plan instanceof MultipleContributionMergePlan) {
- MultipleContributionMergePlan multiPlan =
(MultipleContributionMergePlan)plan;
- multiPlan.addContribution(contribution);
- return multiPlan;
+ ((MultipleContributionMergePlan)plan).addContribution(contribution);
+ return plan;
}
MergePlan newPlan = null;
if (plan instanceof OneContributionMergePlan) {
@@ -160,8 +173,10 @@
*/
private static final long serialVersionUID = 1L;
+ private final ReadWriteLock annotationLock = new ReentrantReadWriteLock();
+ private DateTime expirationTimeInUtc;
+ @GuardedBy( "annotationLock" )
private Map<Name, Property> annotations = null;
- private DateTime expirationTimeInUtc;
/**
* Create an empty merge plan
@@ -180,7 +195,7 @@
public boolean isExpired( DateTime utcTime ) {
assert utcTime != null;
assert utcTime.toUtcTimeZone().equals(utcTime); // check that it is passed UTC
time
- return !expirationTimeInUtc.isAfter(utcTime);
+ return utcTime.isAfter(getExpirationTimeInUtc());
}
/**
@@ -190,6 +205,17 @@
* @return the expiration time in UTC, or null if there is no known expiration time
*/
public DateTime getExpirationTimeInUtc() {
+ if (expirationTimeInUtc == null) {
+ // This is computed regardless of a lock, since it's not expensive and
idempotent
+ DateTime earliest = null;
+ for (Contribution contribution : this) {
+ DateTime contributionTime = contribution.getExpirationTimeInUtc();
+ if (earliest == null || (contributionTime != null &&
contributionTime.isBefore(earliest))) {
+ earliest = contributionTime;
+ }
+ }
+ expirationTimeInUtc = earliest;
+ }
return expirationTimeInUtc;
}
@@ -224,8 +250,13 @@
*/
public Property getAnnotation( Name name ) {
if (name == null) return null;
- if (this.annotations == null) return null;
- return this.annotations.get(name);
+ try {
+ annotationLock.readLock().lock();
+ if (this.annotations == null) return null;
+ return this.annotations.get(name);
+ } finally {
+ annotationLock.readLock().unlock();
+ }
}
/**
@@ -239,21 +270,131 @@
*/
public Property setAnnotation( Property annotation ) {
if (annotation == null) return null;
- if (this.annotations == null) {
- this.annotations = new HashMap<Name, Property>();
+ try {
+ annotationLock.writeLock().lock();
+ if (this.annotations == null) {
+ this.annotations = new HashMap<Name, Property>();
+ }
+ return this.annotations.put(annotation.getName(), annotation);
+ } finally {
+ annotationLock.writeLock().unlock();
}
- return this.annotations.put(annotation.getName(), annotation);
}
+ /**
+ * Get the number of annotations.
+ *
+ * @return the number of annotations
+ */
+ public int getAnnotationCount() {
+ try {
+ annotationLock.readLock().lock();
+ if (this.annotations == null) return 0;
+ return this.annotations.size();
+ } finally {
+ annotationLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the set of annotation {@link Name names}.
+ *
+ * @return the unmodifiable set of names, or an empty set if there are no
annotations
+ */
+ public Set<Name> getAnnotationNames() {
+ try {
+ annotationLock.readLock().lock();
+ if (this.annotations == null) return Collections.emptySet();
+ return Collections.unmodifiableSet(this.annotations.keySet());
+ } finally {
+ annotationLock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Set the annotations. This
+ *
+ * @param annotations
+ */
protected void setAnnotations( Map<Name, Property> annotations ) {
- this.annotations = annotations;
+ try {
+ annotationLock.writeLock().lock();
+ this.annotations = annotations == null || annotations.isEmpty() ? null :
annotations;
+ } finally {
+ annotationLock.writeLock().unlock();
+ }
}
/**
- * @return annotations
+ * Get a copy of the annotations.
+ *
+ * @return a copy of annotations; never null
*/
- protected Map<Name, Property> getAnnotations() {
- return annotations;
+ public Map<Name, Property> getAnnotations() {
+ Map<Name, Property> result = null;
+ try {
+ annotationLock.writeLock().lock();
+ if (this.annotations != null && !this.annotations.isEmpty()) {
+ result = new HashMap<Name, Property>(this.annotations);
+ } else {
+ result = Collections.emptyMap();
+ }
+ } finally {
+ annotationLock.writeLock().unlock();
+ }
+ return result;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (Contribution contribution : this) {
+ if (!first) {
+ first = false;
+ sb.append(", ");
+ }
+ sb.append(contribution);
+ }
+ sb.append(StringUtil.readableString(getAnnotations()));
+ return sb.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof MergePlan) {
+ MergePlan that = (MergePlan)obj;
+ if (this.getContributionCount() != that.getContributionCount()) return
false;
+ Iterator<Contribution> thisContribution = this.iterator();
+ Iterator<Contribution> thatContribution = that.iterator();
+ while (thisContribution.hasNext() && thatContribution.hasNext()) {
+ if (!thisContribution.next().equals(thatContribution.next())) return
false;
+ }
+ if (this.getAnnotationCount() != that.getAnnotationCount()) return false;
+ if (!this.getAnnotations().equals(that.getAnnotations())) return false;
+ return true;
+ }
+ return false;
+ }
+
+ protected boolean checkEachContributionIsFromDistinctSource() {
+ Set<String> sourceNames = new HashSet<String>();
+ for (Contribution contribution : this) {
+ boolean added = sourceNames.add(contribution.getSourceName());
+ if (!added) return false;
+ }
+ return true;
+ }
+
}
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlan.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlan.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlan.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -34,43 +34,43 @@
public class MultipleContributionMergePlan extends MergePlan {
private static final long serialVersionUID = 1L;
- private final List<Contribution> contributions;
+ private final List<Contribution> contributions = new
CopyOnWriteArrayList<Contribution>();
/**
* @param contributions the contributions for this merge plan
*/
- public MultipleContributionMergePlan( Contribution... contributions ) {
+ /*package*/MultipleContributionMergePlan( Contribution... contributions ) {
assert contributions != null;
- this.contributions = new CopyOnWriteArrayList<Contribution>();
for (int i = 0; i != contributions.length; ++i) {
assert contributions[i] != null;
this.contributions.add(contributions[i]);
}
+ assert checkEachContributionIsFromDistinctSource();
}
/**
* @param contributions the contributions for this merge plan
*/
- public MultipleContributionMergePlan( Iterable<Contribution> contributions ) {
+ /*package*/MultipleContributionMergePlan( Iterable<Contribution> contributions
) {
assert contributions != null;
- this.contributions = new CopyOnWriteArrayList<Contribution>();
for (Contribution contribution : contributions) {
assert contribution != null;
this.contributions.add(contribution);
}
+ assert checkEachContributionIsFromDistinctSource();
}
/**
* @param contributions the contributions for this merge plan
*/
- public MultipleContributionMergePlan( Iterator<Contribution> contributions ) {
+ /*package*/MultipleContributionMergePlan( Iterator<Contribution> contributions
) {
assert contributions != null;
- this.contributions = new CopyOnWriteArrayList<Contribution>();
while (contributions.hasNext()) {
Contribution contribution = contributions.next();
assert contribution != null;
this.contributions.add(contribution);
}
+ assert checkEachContributionIsFromDistinctSource();
}
/**
@@ -138,4 +138,14 @@
this.contributions.add(contribution);
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return contributions.hashCode();
+ }
+
}
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/OneContributionMergePlan.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/OneContributionMergePlan.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/OneContributionMergePlan.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -38,7 +38,7 @@
/**
* @param contribution the contribution for this merge plan
*/
- public OneContributionMergePlan( Contribution contribution ) {
+ /*package*/OneContributionMergePlan( Contribution contribution ) {
assert contribution != null;
this.contribution = contribution;
}
@@ -101,4 +101,14 @@
return contribution.getSourceName().equals(sourceName);
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return contribution.hashCode();
+ }
+
}
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/StandardMergeStrategy.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/StandardMergeStrategy.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/StandardMergeStrategy.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -50,5 +50,8 @@
// Children whose identity properties are the same will be considered to be the
same node ...
assert identityPropertyName != null;
+ // Create a merge plan with the contributions ...
+ MergePlan plan = MergePlan.create(contributions);
+ federatedNode.setMergePlan(plan);
}
}
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/ThreeContributionMergePlan.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/ThreeContributionMergePlan.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/ThreeContributionMergePlan.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -24,6 +24,7 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.connector.federation.contribution.Contribution;
/**
@@ -42,15 +43,16 @@
* @param contribution2 the second contribution for this merge plan
* @param contribution3 the third contribution for this merge plan
*/
- public ThreeContributionMergePlan( Contribution contribution1,
- Contribution contribution2,
- Contribution contribution3 ) {
+ /*package*/ThreeContributionMergePlan( Contribution contribution1,
+ Contribution contribution2,
+ Contribution contribution3 ) {
assert contribution1 != null;
assert contribution2 != null;
assert contribution3 != null;
this.contribution1 = contribution1;
this.contribution2 = contribution2;
this.contribution3 = contribution3;
+ assert checkEachContributionIsFromDistinctSource();
}
/**
@@ -125,4 +127,14 @@
return false;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.compute(contribution1, contribution2, contribution3);
+ }
+
}
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/TwoContributionMergePlan.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/TwoContributionMergePlan.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/TwoContributionMergePlan.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -24,6 +24,7 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.connector.federation.contribution.Contribution;
/**
@@ -40,12 +41,13 @@
* @param contribution1 the first contribution for this merge plan
* @param contribution2 the second contribution for this merge plan
*/
- public TwoContributionMergePlan( Contribution contribution1,
- Contribution contribution2 ) {
+ /*package*/TwoContributionMergePlan( Contribution contribution1,
+ Contribution contribution2 ) {
assert contribution1 != null;
assert contribution2 != null;
this.contribution1 = contribution1;
this.contribution2 = contribution2;
+ assert checkEachContributionIsFromDistinctSource();
}
/**
@@ -112,4 +114,14 @@
return contribution1.getSourceName().equals(sourceName) ||
contribution2.getSourceName().equals(sourceName);
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.compute(contribution1, contribution2);
+ }
+
}
Modified:
trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties 2008-08-18
21:38:58 UTC (rev 440)
@@ -21,6 +21,8 @@
#
requiredNodeDoesNotExistRelativeToNode = The required node {0} does not exist relative to
{1}
propertyIsRequired = The {0} property is required but has no value
+nodeDoesNotExistAtPath = No node exists at {0} (or below {1})
+errorRemovingNodeFromCache = Error while removing {0} from cache
interruptedWhileUsingFederationConfigurationRepository = Interrupted while using
federation configuration repository "{0}"
unableToFindFederatedRepositoryInJndi = Unable to find a FederatedRepository instance in
JNDI under "{1}" when creating connection to federated source "{0}"
Modified:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -109,7 +109,7 @@
source.setExecutionContextFactoryJndiName(executionContextFactoryJndiName);
source.setContext(jndiContext);
source.setSecurityDomain(securityDomain);
- configRepository = new SimpleRepository("Configuration Repository");
+ configRepository = SimpleRepository.get("Configuration Repository");
configRepository.setProperty(context, "/dna:repositories/Test
Repository", "dna:timeToExpire", "100000");
configRepository.setProperty(context, "/dna:repositories/Test
Repository", "dna:timeToCache", "100000");
configRepository.setProperty(context, "/dna:repositories/Test
Repository/dna:cache", "dna:projectionRules", "/ => /");
Modified:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionTest.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionTest.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/ProjectionTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -22,6 +22,8 @@
package org.jboss.dna.connector.federation;
import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.hasItems;
import static org.mockito.Mockito.stub;
@@ -227,4 +229,50 @@
Set<Path> pathsInRepository = projection.getPathsInRepository(pathInSource,
pathFactory);
assertThat(pathsInRepository, hasItems(pathInRepository1, pathInRepository23));
}
+
+ @Test
+ public void
shouldParsePathRuleFromDefinitionWithNonRootRepositoryPathAndNonRootSourcePath() {
+ Projection.Rule rule = Projection.parsePathRule("/a => /b",
context);
+ assertThat(rule, is(instanceOf(Projection.PathRule.class)));
+ Projection.PathRule pathRule = (Projection.PathRule)rule;
+ assertThat(pathRule.getPathInRepository(),
is(pathFactory.create("/a")));
+ assertThat(pathRule.getPathInSource(), is(pathFactory.create("/b")));
+ }
+
+ @Test
+ public void
shouldParsePathRuleFromDefinitionWithRootRepositoryPathAndNonRootSourcePath() {
+ Projection.Rule rule = Projection.parsePathRule("/ => /b",
context);
+ assertThat(rule, is(instanceOf(Projection.PathRule.class)));
+ Projection.PathRule pathRule = (Projection.PathRule)rule;
+ assertThat(pathRule.getPathInRepository(), is(pathFactory.createRootPath()));
+ assertThat(pathRule.getPathInSource(), is(pathFactory.create("/b")));
+ }
+
+ @Test
+ public void
shouldParsePathRuleFromDefinitionWithNonRootRepositoryPathAndRootSourcePath() {
+ Projection.Rule rule = Projection.parsePathRule("/a => /",
context);
+ assertThat(rule, is(instanceOf(Projection.PathRule.class)));
+ Projection.PathRule pathRule = (Projection.PathRule)rule;
+ assertThat(pathRule.getPathInRepository(),
is(pathFactory.create("/a")));
+ assertThat(pathRule.getPathInSource(), is(pathFactory.createRootPath()));
+ }
+
+ @Test
+ public void
shouldParsePathRuleFromDefinitionWithRootRepositoryPathAndRootSourcePath() {
+ Projection.Rule rule = Projection.parsePathRule("/ => /", context);
+ assertThat(rule, is(instanceOf(Projection.PathRule.class)));
+ Projection.PathRule pathRule = (Projection.PathRule)rule;
+ assertThat(pathRule.getPathInRepository(), is(pathFactory.createRootPath()));
+ assertThat(pathRule.getPathInSource(), is(pathFactory.createRootPath()));
+ }
+
+ @Test
+ public void
shouldNotParsePathRuleFromDefinitionWithRootRepositoryPathAndNoSourcePath() {
+ assertThat(Projection.parsePathRule("/", context), is(nullValue()));
+ }
+
+ @Test
+ public void
shouldNotParsePathRuleFromDefinitionWithNonRootRepositoryPathAndNoSourcePath() {
+ assertThat(Projection.parsePathRule("a/", context), is(nullValue()));
+ }
}
Modified:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutorTest.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutorTest.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutorTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -21,16 +21,481 @@
*/
package org.jboss.dna.connector.federation.executor;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.jboss.dna.common.collection.IsIteratorContaining.hasItems;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.jboss.dna.connector.federation.Projection;
+import org.jboss.dna.connector.federation.ProjectionParser;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.jboss.dna.spi.ExecutionContext;
+import org.jboss.dna.spi.cache.BasicCachePolicy;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.connector.BasicExecutionContext;
+import org.jboss.dna.spi.connector.RepositoryConnection;
+import org.jboss.dna.spi.connector.RepositoryConnectionFactory;
+import org.jboss.dna.spi.connector.SimpleRepository;
+import org.jboss.dna.spi.connector.SimpleRepositorySource;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
/**
* @author Randall Hauch
*/
public class FederatingCommandExecutorTest {
+ private FederatingCommandExecutor executor;
+ private ExecutionContext context;
+ private PathFactory pathFactory;
+ private String sourceName;
+ private Projection cacheProjection;
+ private CachePolicy cachePolicy;
+ private List<Projection> sourceProjections;
+ private Projection.Rule[] cacheProjectionRules = new Projection.Rule[] {};
+ private SimpleRepositorySource cacheSource;
+ private SimpleRepositorySource source1;
+ private SimpleRepositorySource source2;
+ private SimpleRepositorySource source3;
+ @Mock
+ private RepositoryConnectionFactory connectionFactory;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ context = new BasicExecutionContext();
+ pathFactory = context.getValueFactories().getPathFactory();
+ sourceName = "Federated Source";
+ cachePolicy = new BasicCachePolicy(10L, TimeUnit.SECONDS);
+ cacheSource = new SimpleRepositorySource();
+ cacheSource.setName("Cache");
+ cacheSource.setRepositoryName("Cache Repository");
+ ProjectionParser ruleParser = ProjectionParser.getInstance();
+ cacheProjectionRules = ruleParser.rulesFromStrings(context, "/ =>
/cache/repo/A");
+ cacheProjection = new Projection(cacheSource.getName(), cacheProjectionRules);
+ source1 = new SimpleRepositorySource();
+ source2 = new SimpleRepositorySource();
+ source3 = new SimpleRepositorySource();
+ source1.setName("Source 1");
+ source2.setName("Source 2");
+ source3.setName("Source 3");
+ source1.setRepositoryName("Repository 1");
+ source2.setRepositoryName("Repository 2");
+ source3.setRepositoryName("Repository 3");
+ // Set up the cache policies ...
+ source1.setDefaultCachePolicy(new BasicCachePolicy(100, TimeUnit.SECONDS));
+ source2.setDefaultCachePolicy(new BasicCachePolicy(200, TimeUnit.SECONDS));
+ source3.setDefaultCachePolicy(new BasicCachePolicy(300, TimeUnit.SECONDS));
+ sourceProjections = new ArrayList<Projection>();
+ // Source 1 projects from '/source/one/a' into repository '/a'
+ // and from '/source/one/b' into repository '/b'
+ sourceProjections.add(new Projection(source1.getName(),
ruleParser.rulesFromStrings(context,
+
"/a => /source/one/a",
+
"/b => /source/one/b")));
+ // Source 2 projects from '/source/two/a' into repository '/a'
+ sourceProjections.add(new Projection(source2.getName(),
ruleParser.rulesFromStrings(context, "/a => /source/two/a")));
+ // Source 3 projects everything into repository at root
+ sourceProjections.add(new Projection(source3.getName(),
ruleParser.rulesFromStrings(context, "/ => /")));
+ executor = new FederatingCommandExecutor(context, sourceName, cacheProjection,
cachePolicy, sourceProjections,
+ connectionFactory);
+ //
stub(connectionFactory.createConnection(source1.getName())).toReturn(source1.getConnection());
+
doReturn(source1.getConnection()).when(connectionFactory).createConnection(source1.getName());
+
doReturn(source2.getConnection()).when(connectionFactory).createConnection(source2.getName());
+
doReturn(source3.getConnection()).when(connectionFactory).createConnection(source3.getName());
+
doReturn(cacheSource.getConnection()).when(connectionFactory).createConnection(cacheSource.getName());
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ SimpleRepository.shutdownAll();
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenExecutionContextIsNull() {
+ context = null;
+ executor = new FederatingCommandExecutor(context, sourceName, cacheProjection,
cachePolicy, sourceProjections,
+ connectionFactory);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenSourceNameIsNull() {
+ sourceName = null;
+ executor = new FederatingCommandExecutor(context, sourceName, cacheProjection,
cachePolicy, sourceProjections,
+ connectionFactory);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenSourceNameIsEmpty() {
+ sourceName = "";
+ executor = new FederatingCommandExecutor(context, sourceName, cacheProjection,
cachePolicy, sourceProjections,
+ connectionFactory);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenSourceNameIsBlank() {
+ sourceName = " ";
+ executor = new FederatingCommandExecutor(context, sourceName, cacheProjection,
cachePolicy, sourceProjections,
+ connectionFactory);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenConnectionFactoryIsNull() {
+ connectionFactory = null;
+ executor = new FederatingCommandExecutor(context, sourceName, cacheProjection,
cachePolicy, sourceProjections,
+ connectionFactory);
+ }
+
@Test
- public void shouldDoSomething() {
+ public void shouldNotFailWhenCacheProjectionIsNullAndCachePolicyIsNull() {
+ cachePolicy = null;
+ cacheProjection = null;
+ executor = new FederatingCommandExecutor(context, sourceName, cacheProjection,
cachePolicy, sourceProjections,
+ connectionFactory);
+ }
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCacheProjectionIsNullAndCachePolicyIsNotNull() {
+ cachePolicy = null;
+ executor = new FederatingCommandExecutor(context, sourceName, cacheProjection,
cachePolicy, sourceProjections,
+ connectionFactory);
}
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCacheProjectionIsProvidedToConstructorButCachePolicyIsNot()
{
+ assertThat(cacheProjection, is(nullValue()));
+ cachePolicy = null;
+ executor = new FederatingCommandExecutor(context, sourceName, cacheProjection,
cachePolicy, sourceProjections,
+ connectionFactory);
+ }
+
+ @Test
+ public void shouldHaveCurrentTimeInUtc() {
+ DateTime currentTimeInUtc = executor.getCurrentTimeInUtc();
+ assertThat(currentTimeInUtc, is(notNullValue()));
+ assertThat(currentTimeInUtc.toUtcTimeZone(), is(currentTimeInUtc));
+ }
+
+ @Test
+ public void shouldReturnSameExecutionContextSuppliedToConstructor() {
+ assertThat(executor.getExecutionContext(), is(sameInstance(context)));
+ }
+
+ @Test
+ public void shouldObtainCacheConnectionFromConnectionFactoryThenHoldOntoReference()
throws Exception {
+ RepositoryConnection connection = mock(RepositoryConnection.class);
+
stub(connectionFactory.createConnection(cacheSource.getName())).toReturn(connection);
+ assertThat(executor.getConnectionToCache(), is(sameInstance(connection)));
+ verify(connectionFactory, times(1)).createConnection(cacheSource.getName());
+ // Call it again, and should not ask the factory ...
+ assertThat(executor.getConnectionToCache(), is(sameInstance(connection)));
+ verifyNoMoreInteractions(connectionFactory);
+ }
+
+ @Test
+ public void
shouldObtainRepositoryConnectionFromConnectionFactoryThenHoldOntoReference() throws
Exception {
+ String sourceName = "Some source";
+ Projection projection = mock(Projection.class);
+ stub(projection.getSourceName()).toReturn(sourceName);
+ RepositoryConnection connection = mock(RepositoryConnection.class);
+ stub(connectionFactory.createConnection(sourceName)).toReturn(connection);
+
+ assertThat(executor.getConnection(projection), is(sameInstance(connection)));
+ verify(connectionFactory, times(1)).createConnection(sourceName);
+ // Call it again, and should not ask the factory ...
+ assertThat(executor.getConnection(projection), is(sameInstance(connection)));
+ verifyNoMoreInteractions(connectionFactory);
+ }
+
+ @Test
+ public void shouldCloseHavingNotOpenedConnections() throws Exception {
+ assertThat(executor.getOpenConnections().isEmpty(), is(true));
+ executor.close();
+ assertThat(executor.getOpenConnections().isEmpty(), is(true));
+ verifyNoMoreInteractions(connectionFactory);
+ }
+
+ @Test
+ public void shouldCloseAllOpenConnectionsWhenClosingExecutor() throws Exception {
+ // Load the connections
+ assertThat(executor.getConnectionToCache(), is(notNullValue()));
+ for (Projection projection : executor.getSourceProjections()) {
+ assertThat(executor.getConnection(projection), is(notNullValue()));
+ }
+ verify(connectionFactory).createConnection(cacheSource.getName());
+ verify(connectionFactory).createConnection(source1.getName());
+ verify(connectionFactory).createConnection(source2.getName());
+ verify(connectionFactory).createConnection(source3.getName());
+ assertThat(executor.getOpenConnections().isEmpty(), is(false));
+ // Close the executor and verify all connections have been closed
+ executor.close();
+ assertThat(executor.getOpenConnections().isEmpty(), is(true));
+ verifyNoMoreInteractions(connectionFactory);
+ }
+
+ @Test
+ public void shouldLoadContributionsForRootNodeFromSources() throws Exception {
+ Path path = pathFactory.createRootPath();
+ List<Contribution> contributions = new LinkedList<Contribution>();
+ executor.loadContributionsFromSources(path, null, contributions);
+
+ assertThat(contributions.size(), is(3)); // order is based upon order of
projections
+ assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
+ assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
+ assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
+
+ Path.Segment aSeg = pathFactory.createSegment("a");
+ Path.Segment bSeg = pathFactory.createSegment("b");
+ assertThat(contributions.get(0).getChildren(), hasItems(aSeg, bSeg));
+ assertThat(contributions.get(1).getChildren(), hasItems(aSeg));
+ assertThat(contributions.get(2).getChildrenCount(), is(0));
+ }
+
+ @Test
+ public void shouldLoadContributionsForNonRootNodeWithOneContributionFromSources()
throws Exception {
+ // Set up the content of source 3
+ SimpleRepository repository3 =
SimpleRepository.get(source3.getRepositoryName());
+ repository3.setProperty(context, "/x/y", "desc", "y
escription");
+ repository3.setProperty(context, "/x/y/zA", "desc", "zA
description");
+ repository3.setProperty(context, "/x/y/zB", "desc", "zB
description");
+ repository3.setProperty(context, "/x/y/zC", "desc", "zC
description");
+
+ Path path = pathFactory.create("/x/y"); // from source 3
+ List<Contribution> contributions = new LinkedList<Contribution>();
+ executor.loadContributionsFromSources(path, null, contributions);
+
+ assertThat(contributions.size(), is(3)); // order is based upon order of
projections
+ assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
+ assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
+ assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
+
+ Path.Segment child1 = pathFactory.createSegment("zA");
+ Path.Segment child2 = pathFactory.createSegment("zB");
+ Path.Segment child3 = pathFactory.createSegment("zC");
+ assertThat(contributions.get(0).isEmpty(), is(true));
+ assertThat(contributions.get(1).isEmpty(), is(true));
+ assertThat(contributions.get(2).getChildren(), hasItems(child1, child2,
child3));
+
+ path = pathFactory.create("/x"); // from source 3
+ contributions.clear();
+ executor.loadContributionsFromSources(path, null, contributions);
+
+ assertThat(contributions.size(), is(3)); // order is based upon order of
projections
+ assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
+ assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
+ assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
+
+ child1 = pathFactory.createSegment("y");
+ assertThat(contributions.get(0).isEmpty(), is(true));
+ assertThat(contributions.get(1).isEmpty(), is(true));
+ assertThat(contributions.get(2).getChildren(), hasItems(child1));
+ }
+
+ @Test
+ public void shouldLoadNonRootNodeWithTwoContributionFromSources() throws Exception {
+ // Set up the content of source 1
+ SimpleRepository repository1 =
SimpleRepository.get(source1.getRepositoryName());
+ repository1.setProperty(context, "/source/one/a", "desc",
"source 1 node a escription");
+ repository1.setProperty(context, "/source/one/a/nA", "desc",
"source 1 node nA description");
+ repository1.setProperty(context, "/source/one/a/nB", "desc",
"source 1 node nB description");
+ repository1.setProperty(context, "/source/one/a/nC", "desc",
"source 1 node nC description");
+ repository1.setProperty(context, "/source/one/b", "desc",
"source 1 node b description");
+ repository1.setProperty(context, "/source/one/b/pA", "desc",
"source 1 node pA description");
+ repository1.setProperty(context, "/source/one/b/pB", "desc",
"source 1 node pB description");
+ repository1.setProperty(context, "/source/one/b/pC", "desc",
"source 1 node pC description");
+ // Set up the content of source 2
+ SimpleRepository repository2 =
SimpleRepository.get(source2.getRepositoryName());
+ repository2.setProperty(context, "/source/two/a", "desc",
"source 2 node a escription");
+ repository2.setProperty(context, "/source/two/a/qA", "desc",
"source 2 node qA description");
+ repository2.setProperty(context, "/source/two/a/qB", "desc",
"source 2 node qB description");
+ repository2.setProperty(context, "/source/two/a/qC", "desc",
"source 2 node qC description");
+ // Set up the content of source 3
+ SimpleRepository repository3 =
SimpleRepository.get(source3.getRepositoryName());
+ repository3.setProperty(context, "/x/y", "desc", "y
escription");
+ repository3.setProperty(context, "/x/y/zA", "desc", "zA
description");
+ repository3.setProperty(context, "/x/y/zB", "desc", "zB
description");
+ repository3.setProperty(context, "/x/y/zC", "desc", "zC
description");
+ repository3.setProperty(context, "/b/by", "desc", "by
escription");
+ repository3.setProperty(context, "/b/by/bzA", "desc",
"bzA description");
+ repository3.setProperty(context, "/b/by/bzB", "desc",
"bzB description");
+
+ Path path = pathFactory.create("/b"); // from source 2 and source 3
+ List<Contribution> contributions = new LinkedList<Contribution>();
+ executor.loadContributionsFromSources(path, null, contributions);
+
+ assertThat(contributions.size(), is(3)); // order is based upon order of
projections
+ assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
+ assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
+ assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
+
+ Path.Segment child1 = pathFactory.createSegment("pA");
+ Path.Segment child2 = pathFactory.createSegment("pB");
+ Path.Segment child3 = pathFactory.createSegment("pC");
+ Path.Segment child4 = pathFactory.createSegment("by");
+ assertThat(contributions.get(0).getChildren(), hasItems(child1, child2,
child3));
+ assertThat(contributions.get(1).isEmpty(), is(true));
+ assertThat(contributions.get(2).getChildren(), hasItems(child4));
+
+ path = pathFactory.create("/b/by"); // from source 3
+ contributions.clear();
+ executor.loadContributionsFromSources(path, null, contributions);
+
+ assertThat(contributions.size(), is(2)); // order is based upon order of
projections
+ assertThat(contributions.get(0).getSourceName(), is(source2.getName()));
+ assertThat(contributions.get(1).getSourceName(), is(source3.getName()));
+
+ child1 = pathFactory.createSegment("bzA");
+ child2 = pathFactory.createSegment("bzB");
+ assertThat(contributions.get(0).isEmpty(), is(true));
+ assertThat(contributions.get(1).getChildren(), hasItems(child1));
+ }
+
+ @Test
+ public void shouldLoadNonRootNodeWithThreeContributionFromSources() throws Exception
{
+ // Set up the content of source 1
+ SimpleRepository repository1 =
SimpleRepository.get(source1.getRepositoryName());
+ repository1.setProperty(context, "/source/one/a", "desc",
"source 1 node a escription");
+ repository1.setProperty(context, "/source/one/a/nA", "desc",
"source 1 node nA description");
+ repository1.setProperty(context, "/source/one/a/nB", "desc",
"source 1 node nB description");
+ repository1.setProperty(context, "/source/one/a/nC", "desc",
"source 1 node nC description");
+ repository1.setProperty(context, "/source/one/b", "desc",
"source 1 node b description");
+ repository1.setProperty(context, "/source/one/b/pA", "desc",
"source 1 node pA description");
+ repository1.setProperty(context, "/source/one/b/pB", "desc",
"source 1 node pB description");
+ repository1.setProperty(context, "/source/one/b/pC", "desc",
"source 1 node pC description");
+ // Set up the content of source 2
+ SimpleRepository repository2 =
SimpleRepository.get(source2.getRepositoryName());
+ repository2.setProperty(context, "/source/two/a", "desc",
"source 2 node a escription");
+ repository2.setProperty(context, "/source/two/a/qA", "desc",
"source 2 node qA description");
+ repository2.setProperty(context, "/source/two/a/qB", "desc",
"source 2 node qB description");
+ repository2.setProperty(context, "/source/two/a/qC", "desc",
"source 2 node qC description");
+ // Set up the content of source 3
+ SimpleRepository repository3 =
SimpleRepository.get(source3.getRepositoryName());
+ repository3.setProperty(context, "/x/y", "desc", "y
escription");
+ repository3.setProperty(context, "/x/y/zA", "desc", "zA
description");
+ repository3.setProperty(context, "/x/y/zB", "desc", "zB
description");
+ repository3.setProperty(context, "/x/y/zC", "desc", "zC
description");
+ repository3.setProperty(context, "/b/by", "desc", "by
escription");
+ repository3.setProperty(context, "/b/by/bzA", "desc",
"bzA description");
+ repository3.setProperty(context, "/b/by/bzB", "desc",
"bzB description");
+ repository3.setProperty(context, "/a/ay", "desc", "by
escription");
+ repository3.setProperty(context, "/a/ay/azA", "desc",
"bzA description");
+ repository3.setProperty(context, "/a/ay/azB", "desc",
"bzB description");
+
+ Path path = pathFactory.create("/a"); // from sources 1, 2 and 3
+ List<Contribution> contributions = new LinkedList<Contribution>();
+ executor.loadContributionsFromSources(path, null, contributions);
+
+ assertThat(contributions.size(), is(3)); // order is based upon order of
projections
+ assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
+ assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
+ assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
+
+ Path.Segment child1 = pathFactory.createSegment("nA");
+ Path.Segment child2 = pathFactory.createSegment("nB");
+ Path.Segment child3 = pathFactory.createSegment("nC");
+ Path.Segment child4 = pathFactory.createSegment("qA");
+ Path.Segment child5 = pathFactory.createSegment("qB");
+ Path.Segment child6 = pathFactory.createSegment("qC");
+ Path.Segment child7 = pathFactory.createSegment("ay");
+ assertThat(contributions.get(0).getChildren(), hasItems(child1, child2,
child3));
+ assertThat(contributions.get(1).getChildren(), hasItems(child4, child5,
child6));
+ assertThat(contributions.get(2).getChildren(), hasItems(child7));
+
+ path = pathFactory.create("/a/ay"); // from source 3
+ contributions.clear();
+ executor.loadContributionsFromSources(path, null, contributions);
+
+ assertThat(contributions.size(), is(1)); // order is based upon order of
projections
+ assertThat(contributions.get(0).getSourceName(), is(source3.getName()));
+ child1 = pathFactory.createSegment("azA");
+ child2 = pathFactory.createSegment("azB");
+ assertThat(contributions.get(0).getChildren(), hasItems(child1, child2));
+ }
+
+ @Test
+ public void
shouldFailToLoadNodeFromSourcesWhenTheNodeDoesNotAppearInAnyOfTheSources() throws
Exception {
+ Path nonExistant =
pathFactory.create("/nonExistant/Node/In/AnySource");
+ List<Contribution> contributions = new LinkedList<Contribution>();
+ executor.loadContributionsFromSources(nonExistant, null, contributions);
+ // All of the contributions should be empty ...
+ for (Contribution contribution : contributions) {
+ assertThat(contribution.isEmpty(), is(true));
+ }
+ }
+
+ @Test
+ public void
shouldComputeCachePolicyCorrectlyUsingCurrentTimeAndSourceDefaultCachePolicy() throws
Exception {
+ // Set up the content of source 1
+ SimpleRepository repository1 =
SimpleRepository.get(source1.getRepositoryName());
+ repository1.setProperty(context, "/source/one/a", "desc",
"source 1 node a escription");
+ repository1.setProperty(context, "/source/one/a/nA", "desc",
"source 1 node nA description");
+ repository1.setProperty(context, "/source/one/a/nB", "desc",
"source 1 node nB description");
+ repository1.setProperty(context, "/source/one/a/nC", "desc",
"source 1 node nC description");
+ repository1.setProperty(context, "/source/one/b", "desc",
"source 1 node b description");
+ repository1.setProperty(context, "/source/one/b/pA", "desc",
"source 1 node pA description");
+ repository1.setProperty(context, "/source/one/b/pB", "desc",
"source 1 node pB description");
+ repository1.setProperty(context, "/source/one/b/pC", "desc",
"source 1 node pC description");
+ // Set up the content of source 2
+ SimpleRepository repository2 =
SimpleRepository.get(source2.getRepositoryName());
+ repository2.setProperty(context, "/source/two/a", "desc",
"source 2 node a escription");
+ repository2.setProperty(context, "/source/two/a/qA", "desc",
"source 2 node qA description");
+ repository2.setProperty(context, "/source/two/a/qB", "desc",
"source 2 node qB description");
+ repository2.setProperty(context, "/source/two/a/qC", "desc",
"source 2 node qC description");
+ // Set up the content of source 3
+ SimpleRepository repository3 =
SimpleRepository.get(source3.getRepositoryName());
+ repository3.setProperty(context, "/x/y", "desc", "y
escription");
+ repository3.setProperty(context, "/x/y/zA", "desc", "zA
description");
+ repository3.setProperty(context, "/x/y/zB", "desc", "zB
description");
+ repository3.setProperty(context, "/x/y/zC", "desc", "zC
description");
+ repository3.setProperty(context, "/b/by", "desc", "by
escription");
+ repository3.setProperty(context, "/b/by/bzA", "desc",
"bzA description");
+ repository3.setProperty(context, "/b/by/bzB", "desc",
"bzB description");
+ repository3.setProperty(context, "/a/ay", "desc", "by
escription");
+ repository3.setProperty(context, "/a/ay/azA", "desc",
"bzA description");
+ repository3.setProperty(context, "/a/ay/azB", "desc",
"bzB description");
+
+ Path path = pathFactory.create("/a"); // from sources 1, 2 and 3
+ List<Contribution> contributions = new LinkedList<Contribution>();
+ executor.loadContributionsFromSources(path, null, contributions);
+
+ // Check when the contributions expire ...
+ DateTime nowInUtc = executor.getCurrentTimeInUtc();
+ DateTime nowPlus10InUtc = nowInUtc.plusSeconds(10);
+ DateTime nowPlus110InUtc = nowInUtc.plusSeconds(110);
+ DateTime nowPlus210InUtc = nowInUtc.plusSeconds(210);
+ DateTime nowPlus310InUtc = nowInUtc.plusSeconds(310);
+ assertThat(contributions.size(), is(3)); // order is based upon order of
projections
+ assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
+ assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
+ assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
+ assertThat(contributions.get(0).isExpired(nowPlus10InUtc), is(false));
+ assertThat(contributions.get(0).isExpired(nowPlus110InUtc), is(true));
+ assertThat(contributions.get(1).isExpired(nowPlus10InUtc), is(false));
+ assertThat(contributions.get(1).isExpired(nowPlus210InUtc), is(true));
+ assertThat(contributions.get(2).isExpired(nowPlus10InUtc), is(false));
+ assertThat(contributions.get(2).isExpired(nowPlus210InUtc), is(false));
+ assertThat(contributions.get(2).isExpired(nowPlus310InUtc), is(true));
+ }
+
+ @Test
+ public void shouldGetNodeUsingPath() {
+
+ }
+
}
Deleted:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/BasicFederatedNodeTest.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/BasicFederatedNodeTest.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/BasicFederatedNodeTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -1,41 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.jboss.dna.connector.federation.merge;
-
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @author Randall Hauch
- */
-public class BasicFederatedNodeTest {
-
- @Before
- public void beforeEach() {
- }
-
- @Test
- public void shouldDoSomething() {
-
- }
-
-}
Copied:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java
(from rev 420,
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/BasicFederatedNodeTest.java)
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java
(rev 0)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.merge;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederatedNodeTest {
+
+ @Before
+ public void beforeEach() {
+ }
+
+ @Test
+ public void shouldDoSomething() {
+
+ }
+
+}
Added:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FiveContributionMergePlanTest.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FiveContributionMergePlanTest.java
(rev 0)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FiveContributionMergePlanTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -0,0 +1,133 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.merge;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.stub;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class FiveContributionMergePlanTest {
+
+ private FiveContributionMergePlan plan;
+ @Mock
+ private Contribution contribution1;
+ @Mock
+ private Contribution contribution2;
+ @Mock
+ private Contribution contribution3;
+ @Mock
+ private Contribution contribution4;
+ @Mock
+ private Contribution contribution5;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ stub(contribution1.getSourceName()).toReturn("source1");
+ stub(contribution2.getSourceName()).toReturn("source2");
+ stub(contribution3.getSourceName()).toReturn("source3");
+ stub(contribution4.getSourceName()).toReturn("source4");
+ stub(contribution5.getSourceName()).toReturn("source5");
+ plan = new FiveContributionMergePlan(contribution1, contribution2, contribution3,
contribution4, contribution5);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullFirstContribution() {
+ contribution1 = null;
+ plan = new FiveContributionMergePlan(contribution1, contribution2, contribution3,
contribution4, contribution5);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullSecondContribution() {
+ contribution2 = null;
+ plan = new FiveContributionMergePlan(contribution1, contribution2, contribution3,
contribution4, contribution5);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullThirdContribution() {
+ contribution3 = null;
+ plan = new FiveContributionMergePlan(contribution1, contribution2, contribution3,
contribution4, contribution5);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullFourthContribution() {
+ contribution4 = null;
+ plan = new FiveContributionMergePlan(contribution1, contribution2, contribution3,
contribution4, contribution5);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullFifthContribution() {
+ contribution5 = null;
+ plan = new FiveContributionMergePlan(contribution1, contribution2, contribution3,
contribution4, contribution5);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void
shouldFailWhenCreatingMergePlanWithMultipleContributionsFromTheSameSource() {
+ stub(contribution5.getSourceName()).toReturn("source1");
+ plan = new FiveContributionMergePlan(contribution1, contribution2, contribution3,
contribution4, contribution5);
+ }
+
+ @Test
+ public void shouldReturnIteratorOverContributions() {
+ assertThat(plan, hasItems(contribution1, contribution2, contribution3,
contribution4, contribution5));
+ }
+
+ @Test
+ public void shouldHaveContributionCountOfFive() {
+ assertThat(plan.getContributionCount(), is(5));
+ }
+
+ @Test
+ public void shouldReturnContributionWhenSuppliedNameMatchesContributionsSourceName()
{
+ assertThat(plan.getContributionFrom(contribution1.getSourceName()),
is(sameInstance(contribution1)));
+ assertThat(plan.getContributionFrom(contribution2.getSourceName()),
is(sameInstance(contribution2)));
+ assertThat(plan.getContributionFrom(contribution3.getSourceName()),
is(sameInstance(contribution3)));
+ assertThat(plan.getContributionFrom(contribution4.getSourceName()),
is(sameInstance(contribution4)));
+ assertThat(plan.getContributionFrom(contribution5.getSourceName()),
is(sameInstance(contribution5)));
+ }
+
+ @Test
+ public void
shouldReturnNullContributionWhenSuppliedNameDoesNotMatchContributionsSourceName() {
+ assertThat(plan.getContributionFrom("other source"), is(nullValue()));
+ }
+
+ @Test
+ public void shouldCompareSourceNameOfContributionsWhenCallingIsSource() {
+ assertThat(plan.isSource(contribution1.getSourceName()), is(true));
+ assertThat(plan.isSource(contribution2.getSourceName()), is(true));
+ assertThat(plan.isSource(contribution3.getSourceName()), is(true));
+ assertThat(plan.isSource(contribution4.getSourceName()), is(true));
+ assertThat(plan.isSource(contribution5.getSourceName()), is(true));
+ assertThat(plan.isSource("other source"), is(false));
+ }
+}
Property changes on:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FiveContributionMergePlanTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FourContributionMergePlanTest.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FourContributionMergePlanTest.java
(rev 0)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FourContributionMergePlanTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -0,0 +1,121 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.merge;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.stub;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class FourContributionMergePlanTest {
+
+ private FourContributionMergePlan plan;
+ @Mock
+ private Contribution contribution1;
+ @Mock
+ private Contribution contribution2;
+ @Mock
+ private Contribution contribution3;
+ @Mock
+ private Contribution contribution4;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ stub(contribution1.getSourceName()).toReturn("source1");
+ stub(contribution2.getSourceName()).toReturn("source2");
+ stub(contribution3.getSourceName()).toReturn("source3");
+ stub(contribution4.getSourceName()).toReturn("source4");
+ plan = new FourContributionMergePlan(contribution1, contribution2, contribution3,
contribution4);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullFirstContribution() {
+ contribution1 = null;
+ plan = new FourContributionMergePlan(contribution1, contribution2, contribution3,
contribution4);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullSecondContribution() {
+ contribution2 = null;
+ plan = new FourContributionMergePlan(contribution1, contribution2, contribution3,
contribution4);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullThirdContribution() {
+ contribution3 = null;
+ plan = new FourContributionMergePlan(contribution1, contribution2, contribution3,
contribution4);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullFourthContribution() {
+ contribution4 = null;
+ plan = new FourContributionMergePlan(contribution1, contribution2, contribution3,
contribution4);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void
shouldFailWhenCreatingMergePlanWithMultipleContributionsFromTheSameSource() {
+ plan = new FourContributionMergePlan(contribution1, contribution1, contribution3,
contribution4);
+ }
+
+ @Test
+ public void shouldReturnIteratorOverContributions() {
+ assertThat(plan, hasItems(contribution1, contribution2, contribution3,
contribution4));
+ }
+
+ @Test
+ public void shouldHaveContributionCountOfFour() {
+ assertThat(plan.getContributionCount(), is(4));
+ }
+
+ @Test
+ public void shouldReturnContributionWhenSuppliedNameMatchesContributionsSourceName()
{
+ assertThat(plan.getContributionFrom(contribution1.getSourceName()),
is(sameInstance(contribution1)));
+ assertThat(plan.getContributionFrom(contribution2.getSourceName()),
is(sameInstance(contribution2)));
+ assertThat(plan.getContributionFrom(contribution3.getSourceName()),
is(sameInstance(contribution3)));
+ assertThat(plan.getContributionFrom(contribution4.getSourceName()),
is(sameInstance(contribution4)));
+ }
+
+ @Test
+ public void
shouldReturnNullContributionWhenSuppliedNameDoesNotMatchContributionsSourceName() {
+ assertThat(plan.getContributionFrom("other source"), is(nullValue()));
+ }
+
+ @Test
+ public void shouldCompareSourceNameOfContributionsWhenCallingIsSource() {
+ assertThat(plan.isSource(contribution1.getSourceName()), is(true));
+ assertThat(plan.isSource(contribution2.getSourceName()), is(true));
+ assertThat(plan.isSource(contribution3.getSourceName()), is(true));
+ assertThat(plan.isSource(contribution4.getSourceName()), is(true));
+ assertThat(plan.isSource("other source"), is(false));
+ }
+}
Property changes on:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FourContributionMergePlanTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/MergePlanTest.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/MergePlanTest.java
(rev 0)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/MergePlanTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -0,0 +1,330 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.merge;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.jboss.dna.spi.graph.DateTime;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.impl.BasicEmptyProperty;
+import org.jboss.dna.spi.graph.impl.BasicName;
+import org.jboss.dna.spi.graph.impl.JodaDateTime;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class MergePlanTest {
+
+ private MergePlan plan;
+ private List<Contribution> contributions;
+
+ @Before
+ public void beforeEach() throws Exception {
+ contributions = new ArrayList<Contribution>();
+ }
+
+ protected void addContributions( int number ) {
+ for (int i = 0; i != number; ++i) {
+ Contribution contribution = mock(Contribution.class);
+ stub(contribution.getSourceName()).toReturn("source " + i);
+ contributions.add(contribution);
+ }
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToCreateMergePlanFromArrayWithNoContributions() {
+ MergePlan.create(contributions.toArray(new Contribution[contributions.size()]));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromArrayWithOneContribution() {
+ addContributions(1);
+ plan = MergePlan.create(contributions.toArray(new
Contribution[contributions.size()]));
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(OneContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(1));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromArrayWithTwoContributions() {
+ addContributions(2);
+ plan = MergePlan.create(contributions.toArray(new
Contribution[contributions.size()]));
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(TwoContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(2));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromArrayWithThreeContributions() {
+ addContributions(3);
+ plan = MergePlan.create(contributions.toArray(new
Contribution[contributions.size()]));
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(ThreeContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(3));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromArrayWithFourContributions() {
+ addContributions(4);
+ plan = MergePlan.create(contributions.toArray(new
Contribution[contributions.size()]));
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(FourContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(4));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromArrayWithFiveContributions() {
+ addContributions(5);
+ plan = MergePlan.create(contributions.toArray(new
Contribution[contributions.size()]));
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(FiveContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(5));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromArrayWithSixContributions() {
+ addContributions(6);
+ plan = MergePlan.create(contributions.toArray(new
Contribution[contributions.size()]));
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(MultipleContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(6));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromArrayWithManyContributions() {
+ addContributions(100);
+ plan = MergePlan.create(contributions.toArray(new
Contribution[contributions.size()]));
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(MultipleContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(100));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToCreateMergePlanFromListWithNoContributions() {
+ MergePlan.create(contributions);
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromListWithOneContribution() {
+ addContributions(1);
+ plan = MergePlan.create(contributions);
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(OneContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(1));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromListWithTwoContributions() {
+ addContributions(2);
+ plan = MergePlan.create(contributions);
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(TwoContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(2));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromListWithThreeContributions() {
+ addContributions(3);
+ plan = MergePlan.create(contributions);
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(ThreeContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(3));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromListWithFourContributions() {
+ addContributions(4);
+ plan = MergePlan.create(contributions);
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(FourContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(4));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromListWithFiveContributions() {
+ addContributions(5);
+ plan = MergePlan.create(contributions);
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(FiveContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(5));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromListWithSixContributions() {
+ addContributions(6);
+ plan = MergePlan.create(contributions);
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(MultipleContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(6));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldCreateMergePlanFromListWithManyContributions() {
+ addContributions(100);
+ plan = MergePlan.create(contributions);
+ assertThat(plan, is(instanceOf(MergePlan.class)));
+ assertThat(plan, is(instanceOf(MultipleContributionMergePlan.class)));
+ assertThat(plan.getContributionCount(), is(100));
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldComputeOnlyOnceTheExpirationTimeFromTheContributions() {
+ DateTime nowInUtc = new JodaDateTime().toUtcTimeZone();
+ DateTime nowPlus100InUtc = nowInUtc.plusSeconds(100);
+ DateTime nowPlus200InUtc = nowInUtc.plusSeconds(200);
+
+ addContributions(2);
+ stub(contributions.get(0).getExpirationTimeInUtc()).toReturn(nowPlus100InUtc);
+ stub(contributions.get(1).getExpirationTimeInUtc()).toReturn(nowPlus200InUtc);
+
+ plan = MergePlan.create(contributions);
+ DateTime expires = plan.getExpirationTimeInUtc();
+ assertThat(expires, is(nowPlus100InUtc));
+ verify(contributions.get(0), times(1)).getSourceName();
+ verify(contributions.get(1), times(1)).getSourceName();
+ verify(contributions.get(0), times(1)).getExpirationTimeInUtc();
+ verify(contributions.get(1), times(1)).getExpirationTimeInUtc();
+
+ DateTime expires2 = plan.getExpirationTimeInUtc();
+ assertThat(expires2, is(nowPlus100InUtc));
+ verifyNoMoreInteractions(contributions.get(0));
+ verifyNoMoreInteractions(contributions.get(1));
+ }
+
+ @Test
+ public void shouldDetermineIfExpired() {
+ DateTime nowInUtc = new JodaDateTime().toUtcTimeZone();
+ DateTime nowPlus100InUtc = nowInUtc.plusSeconds(100);
+ DateTime nowPlus200InUtc = nowInUtc.plusSeconds(200);
+ DateTime nowPlus300InUtc = nowInUtc.plusSeconds(300);
+
+ addContributions(2);
+ stub(contributions.get(0).getExpirationTimeInUtc()).toReturn(nowPlus100InUtc);
+ stub(contributions.get(1).getExpirationTimeInUtc()).toReturn(nowPlus200InUtc);
+
+ plan = MergePlan.create(contributions);
+ DateTime expires = plan.getExpirationTimeInUtc();
+ assertThat(expires, is(nowPlus100InUtc));
+ verify(contributions.get(0), times(1)).getExpirationTimeInUtc();
+ verify(contributions.get(1), times(1)).getExpirationTimeInUtc();
+ assertThat(plan.isExpired(nowInUtc), is(false));
+ assertThat(plan.isExpired(nowPlus100InUtc), is(false));
+ assertThat(plan.isExpired(nowPlus200InUtc), is(true));
+ assertThat(plan.isExpired(nowPlus300InUtc), is(true));
+ }
+
+ @Test
+ public void shouldHaveNoAnnotationsUponConstruction() {
+ addContributions(2);
+ plan = MergePlan.create(contributions);
+ assertThat(plan.getAnnotationCount(), is(0));
+ }
+
+ @Test
+ public void
shouldAllowSettingAnnotationAndShouldReturnNullWhenSettingNullAnnotation() {
+ addContributions(2);
+ plan = MergePlan.create(contributions);
+ assertThat(plan.setAnnotation(null), is(nullValue()));
+ }
+
+ @Test
+ public void
shouldAllowSettingAnnotationAndShouldReturnPreviousPropertyWhenSettingAnnotation() {
+ Property property = new BasicEmptyProperty(new BasicName("uri",
"name"));
+ Property property2 = new BasicEmptyProperty(property.getName());
+
+ addContributions(2);
+ plan = MergePlan.create(contributions);
+ assertThat(plan.setAnnotation(property), is(nullValue()));
+ assertThat(plan.setAnnotation(property2), is(property));
+ }
+
+ @SuppressWarnings( "unchecked" )
+ @Test
+ public void shouldSetAnnotationsMapToNullIfPassedNullOrEmptyMap() {
+ addContributions(2);
+ plan = MergePlan.create(contributions);
+ plan.setAnnotations(null);
+ assertThat(plan.getAnnotationCount(), is(0));
+
+ Map<Name, Property> newAnnotations = mock(Map.class);
+ plan.setAnnotations(newAnnotations);
+ assertThat(plan.getAnnotationCount(), is(0));
+ verify(newAnnotations).size();
+ }
+
+ @SuppressWarnings( "unchecked" )
+ @Test
+ public void shouldSetAnnotationsMapToSameInstancePassedIn() {
+ addContributions(2);
+ plan = MergePlan.create(contributions);
+ Map<Name, Property> newAnnotations = mock(Map.class);
+ stub(newAnnotations.size()).toReturn(3);
+ plan.setAnnotations(newAnnotations);
+ assertThat(plan.getAnnotationCount(), is(3));
+ verify(newAnnotations).size();
+ }
+
+ @Test
+ public void shouldReturnCopyOfAnnotationsMapFromGetAnnotations() {
+ Property property = new BasicEmptyProperty(new BasicName("uri",
"name"));
+ Map<Name, Property> annotations = new HashMap<Name, Property>();
+ annotations.put(property.getName(), property);
+
+ addContributions(2);
+ plan = MergePlan.create(contributions);
+ plan.setAnnotations(annotations);
+ Map<Name, Property> annotationsCopy = plan.getAnnotations();
+ assertThat(annotationsCopy, is(not(sameInstance(annotations))));
+ }
+}
Property changes on:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/MergePlanTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlanTest.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlanTest.java
(rev 0)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlanTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -0,0 +1,125 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.merge;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.util.LinkedList;
+import java.util.List;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class MultipleContributionMergePlanTest {
+
+ private MultipleContributionMergePlan plan;
+ private List<Contribution> contributions;
+
+ @Before
+ public void beforeEach() throws Exception {
+ contributions = new LinkedList<Contribution>();
+ addContributions(10);
+ plan = new MultipleContributionMergePlan(contributions);
+ }
+
+ protected void addContributions( int number ) {
+ for (int i = 0; i != number; ++i) {
+ Contribution contribution = mock(Contribution.class);
+ stub(contribution.getSourceName()).toReturn("source " + i);
+ contributions.add(contribution);
+ }
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullFirstContribution() {
+ contributions.add(0, null);
+ plan = new MultipleContributionMergePlan(contributions);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullSecondContribution() {
+ contributions.add(1, null);
+ plan = new MultipleContributionMergePlan(contributions);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullThirdContribution() {
+ contributions.add(2, null);
+ plan = new MultipleContributionMergePlan(contributions);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullFourthContribution() {
+ contributions.add(3, null);
+ plan = new MultipleContributionMergePlan(contributions);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullFifthContribution() {
+ contributions.add(4, null);
+ plan = new MultipleContributionMergePlan(contributions);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void
shouldFailWhenCreatingMergePlanWithMultipleContributionsFromTheSameSource() {
+ contributions.add(contributions.get(0));
+ plan = new MultipleContributionMergePlan(contributions);
+ }
+
+ @Test
+ public void shouldReturnIteratorOverContributions() {
+ assertThat(plan, hasItems(contributions.toArray(new
Contribution[contributions.size()])));
+ }
+
+ @Test
+ public void shouldHaveContributionCountOfFive() {
+ assertThat(plan.getContributionCount(), is(contributions.size()));
+ }
+
+ @Test
+ public void shouldReturnContributionWhenSuppliedNameMatchesContributionsSourceName()
{
+ for (Contribution contribution : contributions) {
+ assertThat(plan.getContributionFrom(contribution.getSourceName()),
is(sameInstance(contribution)));
+ }
+ }
+
+ @Test
+ public void
shouldReturnNullContributionWhenSuppliedNameDoesNotMatchContributionsSourceName() {
+ assertThat(plan.getContributionFrom("other source"), is(nullValue()));
+ }
+
+ @Test
+ public void shouldCompareSourceNameOfContributionsWhenCallingIsSource() {
+ for (Contribution contribution : contributions) {
+ assertThat(plan.isSource(contribution.getSourceName()), is(true));
+ }
+ assertThat(plan.isSource("other source"), is(false));
+ }
+}
Property changes on:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/MultipleContributionMergePlanTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/OneContributionMergePlanTest.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/OneContributionMergePlanTest.java
(rev 0)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/OneContributionMergePlanTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -0,0 +1,88 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.merge;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItem;
+import static org.mockito.Mockito.stub;
+import java.util.Iterator;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class OneContributionMergePlanTest {
+
+ private OneContributionMergePlan plan;
+ @Mock
+ private Contribution contribution1;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ plan = new OneContributionMergePlan(contribution1);
+ stub(contribution1.getSourceName()).toReturn("source");
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullFirstContribution() {
+ contribution1 = null;
+ plan = new OneContributionMergePlan(contribution1);
+ }
+
+ @Test
+ public void shouldReturnIteratorOverContributions() {
+ Iterator<Contribution> iter = plan.iterator();
+ assertThat(iter.hasNext(), is(true));
+ assertThat(iter.next(), is(sameInstance(contribution1)));
+ assertThat(iter.hasNext(), is(false));
+ assertThat(plan, hasItem(contribution1));
+ }
+
+ @Test
+ public void shouldHaveContributionCountOfOne() {
+ assertThat(plan.getContributionCount(), is(1));
+ }
+
+ @Test
+ public void shouldReturnContributionWhenSuppliedNameMatchesContributionsSourceName()
{
+ assertThat(plan.getContributionFrom(contribution1.getSourceName()),
is(sameInstance(contribution1)));
+ }
+
+ @Test
+ public void
shouldReturnNullContributionWhenSuppliedNameDoesNotMatchContributionsSourceName() {
+ assertThat(plan.getContributionFrom("other source"), is(nullValue()));
+ }
+
+ @Test
+ public void shouldCompareSourceNameOfContributionsWhenCallingIsSource() {
+ assertThat(plan.isSource(contribution1.getSourceName()), is(true));
+ assertThat(plan.isSource("other source"), is(false));
+ }
+}
Property changes on:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/OneContributionMergePlanTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/ThreeContributionMergePlanTest.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/ThreeContributionMergePlanTest.java
(rev 0)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/ThreeContributionMergePlanTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -0,0 +1,110 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.merge;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.stub;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class ThreeContributionMergePlanTest {
+
+ private ThreeContributionMergePlan plan;
+ @Mock
+ private Contribution contribution1;
+ @Mock
+ private Contribution contribution2;
+ @Mock
+ private Contribution contribution3;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ stub(contribution1.getSourceName()).toReturn("source1");
+ stub(contribution2.getSourceName()).toReturn("source2");
+ stub(contribution3.getSourceName()).toReturn("source3");
+ plan = new ThreeContributionMergePlan(contribution1, contribution2,
contribution3);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullFirstContribution() {
+ contribution1 = null;
+ plan = new ThreeContributionMergePlan(contribution1, contribution2,
contribution3);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullSecondContribution() {
+ contribution2 = null;
+ plan = new ThreeContributionMergePlan(contribution1, contribution2,
contribution3);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullThirdContribution() {
+ contribution3 = null;
+ plan = new ThreeContributionMergePlan(contribution1, contribution2,
contribution3);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void
shouldFailWhenCreatingMergePlanWithMultipleContributionsFromTheSameSource() {
+ plan = new ThreeContributionMergePlan(contribution1, contribution2,
contribution1);
+ }
+
+ @Test
+ public void shouldReturnIteratorOverContributions() {
+ assertThat(plan, hasItems(contribution1, contribution2, contribution3));
+ }
+
+ @Test
+ public void shouldHaveContributionCountOfThree() {
+ assertThat(plan.getContributionCount(), is(3));
+ }
+
+ @Test
+ public void shouldReturnContributionWhenSuppliedNameMatchesContributionsSourceName()
{
+ assertThat(plan.getContributionFrom(contribution1.getSourceName()),
is(sameInstance(contribution1)));
+ assertThat(plan.getContributionFrom(contribution2.getSourceName()),
is(sameInstance(contribution2)));
+ assertThat(plan.getContributionFrom(contribution3.getSourceName()),
is(sameInstance(contribution3)));
+ }
+
+ @Test
+ public void
shouldReturnNullContributionWhenSuppliedNameDoesNotMatchContributionsSourceName() {
+ assertThat(plan.getContributionFrom("other source"), is(nullValue()));
+ }
+
+ @Test
+ public void shouldCompareSourceNameOfContributionsWhenCallingIsSource() {
+ assertThat(plan.isSource(contribution1.getSourceName()), is(true));
+ assertThat(plan.isSource(contribution2.getSourceName()), is(true));
+ assertThat(plan.isSource(contribution3.getSourceName()), is(true));
+ assertThat(plan.isSource("other source"), is(false));
+ }
+}
Property changes on:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/ThreeContributionMergePlanTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/TwoContributionMergePlanTest.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/TwoContributionMergePlanTest.java
(rev 0)
+++
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/TwoContributionMergePlanTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -0,0 +1,99 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.dna.connector.federation.merge;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.stub;
+import org.jboss.dna.connector.federation.contribution.Contribution;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class TwoContributionMergePlanTest {
+
+ private TwoContributionMergePlan plan;
+ @Mock
+ private Contribution contribution1;
+ @Mock
+ private Contribution contribution2;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ stub(contribution1.getSourceName()).toReturn("source1");
+ stub(contribution2.getSourceName()).toReturn("source2");
+ plan = new TwoContributionMergePlan(contribution1, contribution2);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullFirstContribution() {
+ contribution1 = null;
+ plan = new TwoContributionMergePlan(contribution1, contribution2);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldFailWhenCreatingMergePlanWithNullSecondContribution() {
+ contribution2 = null;
+ plan = new TwoContributionMergePlan(contribution1, contribution2);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void
shouldFailWhenCreatingMergePlanWithMultipleContributionsFromTheSameSource() {
+ plan = new TwoContributionMergePlan(contribution1, contribution1);
+ }
+
+ @Test
+ public void shouldReturnIteratorOverContributions() {
+ assertThat(plan, hasItems(contribution1, contribution2));
+ }
+
+ @Test
+ public void shouldHaveContributionCountOfTwo() {
+ assertThat(plan.getContributionCount(), is(2));
+ }
+
+ @Test
+ public void shouldReturnContributionWhenSuppliedNameMatchesContributionsSourceName()
{
+ assertThat(plan.getContributionFrom(contribution1.getSourceName()),
is(sameInstance(contribution1)));
+ assertThat(plan.getContributionFrom(contribution2.getSourceName()),
is(sameInstance(contribution2)));
+ }
+
+ @Test
+ public void
shouldReturnNullContributionWhenSuppliedNameDoesNotMatchContributionsSourceName() {
+ assertThat(plan.getContributionFrom("other source"), is(nullValue()));
+ }
+
+ @Test
+ public void shouldCompareSourceNameOfContributionsWhenCallingIsSource() {
+ assertThat(plan.isSource(contribution1.getSourceName()), is(true));
+ assertThat(plan.isSource(contribution2.getSourceName()), is(true));
+ assertThat(plan.isSource("other source"), is(false));
+ }
+}
Property changes on:
trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/TwoContributionMergePlanTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties
(rev 0)
+++
trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties 2008-08-18
21:38:58 UTC (rev 440)
@@ -0,0 +1,17 @@
+# Direct log messages to stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %m%n
+
+# Root logger option
+log4j.rootLogger=INFO, stdout
+
+# Set up the default logging to be INFO level, then override specific units
+log4j.logger.org.jboss.dna=INFO
+log4j.logger.org.jboss.dna.connector.federation.executor=TRACE
+
+# Jackrabbit logging
+log4j.logger.org.apache.jackrabbit=WARN, stdout
+log4j.logger.org.apache.derby=INFO, stdout
+
Property changes on:
trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified:
trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheSourceTest.java
===================================================================
---
trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheSourceTest.java 2008-08-18
18:45:57 UTC (rev 439)
+++
trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheSourceTest.java 2008-08-18
21:38:58 UTC (rev 440)
@@ -32,6 +32,7 @@
import java.util.Hashtable;
import java.util.Map;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
@@ -153,7 +154,7 @@
@Test
public void shouldCreateJndiReferenceAndRecreatedObjectFromReference() throws
Exception {
BasicCachePolicy cachePolicy = new BasicCachePolicy();
- cachePolicy.setTimeToLive(1000L);
+ cachePolicy.setTimeToLive(1000L, TimeUnit.MILLISECONDS);
convertToAndFromJndiReference(validName,
validRootNodeUuid,
validCacheConfigurationName,
@@ -167,7 +168,7 @@
@Test
public void
shouldCreateJndiReferenceAndRecreatedObjectFromReferenceWithNullProperties() throws
Exception {
BasicCachePolicy cachePolicy = new BasicCachePolicy();
- cachePolicy.setTimeToLive(1000L);
+ cachePolicy.setTimeToLive(1000L, TimeUnit.MILLISECONDS);
convertToAndFromJndiReference("some source", null, null, null, null,
null, null, 100);
convertToAndFromJndiReference(null, null, null, null, null, null, null, 100);
}