[dna-commits] DNA SVN: r253 - in trunk: dna-repository/src/main/java/org/jboss/dna/repository and 14 other directories.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Tue Jun 10 16:19:15 EDT 2008


Author: rhauch
Date: 2008-06-10 16:19:15 -0400 (Tue, 10 Jun 2008)
New Revision: 253

Added:
   trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryTest.java
   trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperations.java
   trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/TimeDelayingRepositorySource.java
Removed:
   trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/MockRepositorySource.java
   trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryTestOperations.java
Modified:
   trunk/dna-repository/pom.xml
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/ObservationService.java
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleService.java
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencingService.java
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AbstractServiceAdministrator.java
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/ServiceAdministrator.java
   trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
   trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java
   trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencingServiceTest.java
   trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/JndiSessionFactoryTest.java
   trunk/dna-repository/src/test/resources/log4j.properties
   trunk/dna-spi/pom.xml
   trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java
   trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperation.java
   trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPoolTest.java
   trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositorySourceLoadHarness.java
   trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/BooleanValueFactoryTest.java
   trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/DecimalValueFactoryTest.java
   trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/DoubleValueFactoryTest.java
   trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/JodaDateTimeTest.java
   trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/JodaDateTimeValueFactoryTest.java
   trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/LongValueFactoryTest.java
Log:
DNA-117: Create a FederatedRepository class that manages multiple sources
http://jira.jboss.org/jira/browse/DNA-117

More fully implemented FederatedRepository and added unit tests that cover mode code and cases.

Modified: trunk/dna-repository/pom.xml
===================================================================
--- trunk/dna-repository/pom.xml	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/pom.xml	2008-06-10 20:19:15 UTC (rev 253)
@@ -68,16 +68,6 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.jmock</groupId>
-      <artifactId>jmock</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.jmock</groupId>
-      <artifactId>jmock-junit4</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-all</artifactId>
       <scope>test</scope>

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -34,6 +34,7 @@
     public static I18n invalidStateString;
     public static I18n serviceShutdowAndMayNotBeStarted;
     public static I18n serviceShutdowAndMayNotBePaused;
+    public static I18n serviceNotShutdowAndMayNotBeTerminated;
     public static I18n unableToFindRepositoryInJndi;
     public static I18n unableToRegisterRepositoryInJndi;
     public static I18n unableToUnregisterRepositoryInJndi;
@@ -104,9 +105,9 @@
     public static I18n invalidRepositoryNodePath;
 
     // XML Sequencer
-	public static I18n errorSequencingXmlDocument;
-	public static I18n sequencingXmlDocument;
-	public static I18n canceledSequencingXmlDocument;
+    public static I18n errorSequencingXmlDocument;
+    public static I18n sequencingXmlDocument;
+    public static I18n canceledSequencingXmlDocument;
 
     public static I18n interruptedWhileConnectingToFederationConfigurationRepository;
     public static I18n interruptedWhileClosingConnectionToFederationConfigurationRepository;

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -33,6 +33,7 @@
 import org.jboss.dna.repository.services.AbstractServiceAdministrator;
 import org.jboss.dna.repository.services.ServiceAdministrator;
 import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
 import org.jboss.dna.spi.graph.connection.RepositoryConnectionPool;
 import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
 
@@ -82,6 +83,14 @@
             return FederatedRepository.this.awaitTermination(timeout, unit);
         }
 
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        protected boolean doCheckIsTerminated() {
+            return FederatedRepository.this.isTerminated();
+        }
+
     }
 
     private final ServiceAdministrator administrator = new Administrator();
@@ -107,6 +116,13 @@
     }
 
     /**
+     * @return service
+     */
+    protected FederationService getService() {
+        return this.service;
+    }
+
+    /**
      * Get the name of this repository
      * 
      * @return name
@@ -127,6 +143,7 @@
      */
     protected void startRepository() {
         // Do not establish connections to the sources; these will be established as needed
+
     }
 
     /**
@@ -165,6 +182,50 @@
     }
 
     /**
+     * Returns true if this federated repository is in the process of terminating after {@link ServiceAdministrator#shutdown()}
+     * has been called on the {@link #getAdministrator() administrator}, but the federated repository has connections that have
+     * not yet normally been {@link RepositoryConnection#close() closed}. This method may be useful for debugging. A return of
+     * <tt>true</tt> reported a sufficient period after shutdown may indicate that connection users have ignored or suppressed
+     * interruption, causing this repository not to properly terminate.
+     * 
+     * @return true if terminating but not yet terminated, or false otherwise
+     * @see #isTerminated()
+     */
+    public boolean isTerminating() {
+        try {
+            this.sourcesWriteLock.lock();
+            for (FederatedSource source : this.sources) {
+                if (source.getConnectionPool().isTerminating()) {
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            this.sourcesWriteLock.unlock();
+        }
+    }
+
+    /**
+     * Return true if this federated repository has completed its termination and no longer has any open connections.
+     * 
+     * @return true if terminated, or false otherwise
+     * @see #isTerminating()
+     */
+    public boolean isTerminated() {
+        try {
+            this.sourcesWriteLock.lock();
+            for (FederatedSource source : this.sources) {
+                if (!source.getConnectionPool().isTerminated()) {
+                    return false;
+                }
+            }
+            return true;
+        } finally {
+            this.sourcesWriteLock.unlock();
+        }
+    }
+
+    /**
      * Get an unmodifiable collection of {@link FederatedSource federated sources}.
      * <p>
      * This method can safely be called while the federation repository is in use.
@@ -287,10 +348,12 @@
      * the supplied listener is null.
      * 
      * @param listener the new listener
+     * @return true if the listener was added, or false if the listener was not added (if reference is null, or if non-null
+     * listener is already an existing listener)
      */
-    public void addListener( RepositorySourceListener listener ) {
-        if (listener == null) return;
-        this.listeners.addIfAbsent(listener);
+    public boolean addListener( RepositorySourceListener listener ) {
+        if (listener == null) return false;
+        return this.listeners.addIfAbsent(listener);
     }
 
     /**
@@ -308,6 +371,15 @@
     }
 
     /**
+     * Get the list of listeners, which is the actual list used by the repository.
+     * 
+     * @return the listeners
+     */
+    public List<RepositorySourceListener> getListeners() {
+        return this.listeners;
+    }
+
+    /**
      * Authenticate the supplied username with the supplied credentials, and return whether authentication was successful.
      * 
      * @param username the username

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -117,6 +117,11 @@
         if (!this.repository.getAdministrator().isStarted()) {
             throw new RepositorySourceException(RepositoryI18n.repositoryHasBeenShutDown.text(this.repository.getName()));
         }
+        if (commands == null || commands.length == 0) return;
+
+        for (GraphCommand command : commands) {
+            if (command == null) continue;
+        }
     }
 
     /**

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -25,8 +25,10 @@
 import net.jcip.annotations.ThreadSafe;
 import org.jboss.dna.common.util.ArgCheck;
 import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactory;
 import org.jboss.dna.spi.graph.connection.RepositoryConnectionPool;
 import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
 
 /**
  * A component that represents a {@link RepositorySource repository source} (with its state) being federated in a
@@ -35,7 +37,7 @@
  * @author Randall Hauch
  */
 @ThreadSafe
-public class FederatedSource {
+public class FederatedSource implements RepositoryConnectionFactory {
 
     private final RepositorySource source;
     private final RepositoryConnectionPool connectionPool;
@@ -46,6 +48,12 @@
         this.connectionPool = new RepositoryConnectionPool(source);
     }
 
+    protected FederatedSource( RepositorySource source, RepositoryConnectionPool connectionPool ) {
+        ArgCheck.isNotNull(source, "source");
+        this.source = source;
+        this.connectionPool = connectionPool;
+    }
+
     /**
      * Get the name for this federated repository source.
      * 
@@ -74,6 +82,13 @@
     }
 
     /**
+     * {@inheritDoc}
+     */
+    public RepositoryConnection getConnection() throws RepositorySourceException, InterruptedException {
+        return this.connectionPool.getConnection();
+    }
+
+    /**
      * Determine whether the federated source is available by attempting to connect to the source and
      * {@link RepositoryConnection#ping(long, TimeUnit) pinging} the source.
      * 

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -72,10 +72,18 @@
         /**
          * {@inheritDoc}
          */
-        public boolean awaitTermination( long timeout, TimeUnit unit ) {
-            return true;
+        @Override
+        protected boolean doCheckIsTerminated() {
+            return FederationService.this.isTerminated();
         }
 
+        /**
+         * {@inheritDoc}
+         */
+        public boolean awaitTermination( long timeout, TimeUnit unit ) throws InterruptedException {
+            return FederationService.this.awaitTermination(timeout, unit);
+        }
+
     }
 
     private final RepositorySource configurationSource;
@@ -164,6 +172,24 @@
         }
     }
 
+    protected boolean isTerminated() {
+        // Now shut down all repositories ...
+        for (String repositoryName : this.repositories.keySet()) {
+            FederatedRepository repository = this.repositories.get(repositoryName);
+            if (!repository.getAdministrator().isTerminated()) return false;
+        }
+        return true;
+    }
+
+    protected boolean awaitTermination( long timeout, TimeUnit unit ) throws InterruptedException {
+        // Now shut down all repositories ...
+        for (String repositoryName : this.repositories.keySet()) {
+            FederatedRepository repository = this.repositories.get(repositoryName);
+            if (repository.getAdministrator().awaitTermination(timeout, unit)) return false;
+        }
+        return true;
+    }
+
     /**
      * Create a {@link RepositorySource} that can be used to establish connections to the federated repository with the supplied
      * name.

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/ObservationService.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/ObservationService.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/observation/ObservationService.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -56,6 +56,7 @@
 
     /**
      * Interface to which problems with particular events are logged.
+     * 
      * @author Randall Hauch
      */
     public static interface ProblemLog {
@@ -65,6 +66,7 @@
 
     /**
      * Problem log implementation that records problems in the log.
+     * 
      * @author Randall Hauch
      */
     public class DefaultProblemLog implements ProblemLog {
@@ -90,6 +92,7 @@
 
     /**
      * The administrative component for this service.
+     * 
      * @author Randall Hauch
      */
     protected class Administrator extends AbstractServiceAdministrator {
@@ -114,6 +117,14 @@
             return true;
         }
 
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        protected boolean doCheckIsTerminated() {
+            return true;
+        }
+
     }
 
     private Logger logger = Logger.getLogger(this.getClass());
@@ -146,6 +157,7 @@
 
     /**
      * Get the statistics for this system.
+     * 
      * @return the statistics, which are updated as the system is used
      */
     public Statistics getStatistics() {
@@ -154,6 +166,7 @@
 
     /**
      * Get the logger for this system
+     * 
      * @return the logger
      */
     public Logger getLogger() {
@@ -162,6 +175,7 @@
 
     /**
      * Set the logger for this system.
+     * 
      * @param logger the logger, or null if the standard logging should be used
      */
     public void setLogger( Logger logger ) {
@@ -177,6 +191,7 @@
 
     /**
      * Set the problem log that will be notified of problems handling events. By default, such problems are sent to the log.
+     * 
      * @param problemLog the new problem log implementation; if null, then the default problem log is used
      */
     public void setProblemLog( ProblemLog problemLog ) {
@@ -256,6 +271,7 @@
      * The filters of an already-registered {@link WorkspaceListener} can be changed at runtime by changing the attributes and
      * {@link WorkspaceListener#reregister() registering}.
      * </p>
+     * 
      * @param repositoryWorkspaceName the name to be used with the session factory to obtain a session to the repository and
      * workspace that is to be monitored
      * @param absolutePath the absolute path of the node at or below which changes are to be monitored; may be null if all nodes
@@ -292,6 +308,7 @@
      * needed, it simply must be {@link ObservationManager#removeEventListener(EventListener) removed} as a listener of the
      * workspace and garbage collected.
      * </p>
+     * 
      * @param repositoryWorkspaceName the name to be used with the session factory to obtain a session to the repository and
      * workspace that is to be monitored
      * @param absolutePath the absolute path of the node at or below which changes are to be monitored; may be null if all nodes
@@ -317,6 +334,7 @@
      * needed, it simply must be {@link ObservationManager#removeEventListener(EventListener) removed} as a listener of the
      * workspace and garbage collected.
      * </p>
+     * 
      * @param repositoryWorkspaceName the name to be used with the session factory to obtain a session to the repository and
      * workspace that is to be monitored
      * @param eventTypes the bitmask of the {@link Event} types that are to be monitored
@@ -341,6 +359,7 @@
      * made but excluding those to which that particular listener is not entitled, according to the listeners access permissions
      * and filters.
      * </p>
+     * 
      * @param events
      * @param listener
      */
@@ -460,6 +479,7 @@
 
     /**
      * Implementation of the {@link EventListener JCR EventListener} interface, returned by the sequencing system.
+     * 
      * @author Randall Hauch
      */
     @ThreadSafe
@@ -617,6 +637,7 @@
 
     /**
      * The statistics for the system. Each sequencing system has an instance of this class that is updated.
+     * 
      * @author Randall Hauch
      */
     @ThreadSafe

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleService.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleService.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/rules/RuleService.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -70,6 +70,7 @@
  * the same time, all executions will be properly synchronized with methods to {@link #addRuleSet(RuleSet) add},
  * {@link #updateRuleSet(RuleSet) update}, and {@link #removeRuleSet(String) remove} rule sets.
  * </p>
+ * 
  * @author Randall Hauch
  */
 @ThreadSafe
@@ -79,6 +80,7 @@
 
     /**
      * The administrative component for this service.
+     * 
      * @author Randall Hauch
      */
     protected class Administrator extends AbstractServiceAdministrator {
@@ -100,6 +102,14 @@
         /**
          * {@inheritDoc}
          */
+        @Override
+        protected boolean doCheckIsTerminated() {
+            return RuleService.this.isTerminated();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
         public boolean awaitTermination( long timeout, TimeUnit unit ) throws InterruptedException {
             return doAwaitTermination(timeout, unit);
         }
@@ -124,6 +134,7 @@
 
     /**
      * Return the administrative component for this service.
+     * 
      * @return the administrative component; never null
      */
     public ServiceAdministrator getAdministrator() {
@@ -134,6 +145,7 @@
      * Get the class loader factory that should be used to load sequencers. By default, this service uses a factory that will
      * return either the {@link Thread#getContextClassLoader() current thread's context class loader} (if not null) or the class
      * loader that loaded this class.
+     * 
      * @return the class loader factory; never null
      * @see #setClassLoaderFactory(ClassLoaderFactory)
      */
@@ -145,6 +157,7 @@
      * Set the Maven Repository that should be used to load the sequencer classes. By default, this service uses a class loader
      * factory that will return either the {@link Thread#getContextClassLoader() current thread's context class loader} (if not
      * null) or the class loader that loaded this class.
+     * 
      * @param classLoaderFactory the class loader factory reference, or null if the default class loader factory should be used.
      * @see #getClassLoaderFactory()
      */
@@ -154,6 +167,7 @@
 
     /**
      * Obtain the rule sets that are currently available in this service.
+     * 
      * @return an unmodifiable copy of the rule sets; never null, but possibly empty ...
      */
     public Collection<RuleSet> getRuleSets() {
@@ -170,6 +184,7 @@
 
     /**
      * Add a rule set, or update any existing one that represents the {@link RuleSet#equals(Object) same rule set}
+     * 
      * @param ruleSet the new rule set
      * @return true if the rule set was added, or false if the rule set was not added (because it wasn't necessary)
      * @throws IllegalArgumentException if <code>ruleSet</code> is null
@@ -266,6 +281,7 @@
 
     /**
      * Update the configuration for a sequencer, or add it if there is no {@link RuleSet#equals(Object) matching configuration}.
+     * 
      * @param ruleSet the rule set to be updated
      * @return true if the rule set was updated, or false if the rule set was not updated (because it wasn't necessary)
      * @throws InvalidRuleSetException if the supplied rule set is invalid, incomplete, incorrectly defined, or uses a JSR-94
@@ -279,6 +295,7 @@
 
     /**
      * Remove a rule set.
+     * 
      * @param ruleSetName the name of the rule set to be removed
      * @return true if the rule set was removed, or if it was not an existing rule set
      * @throws IllegalArgumentException if <code>ruleSetName</code> is null or empty
@@ -310,6 +327,7 @@
 
     /**
      * Get the logger for this system
+     * 
      * @return the logger
      */
     public Logger getLogger() {
@@ -318,6 +336,7 @@
 
     /**
      * Set the logger for this system.
+     * 
      * @param logger the logger, or null if the standard logging should be used
      */
     public void setLogger( Logger logger ) {
@@ -328,6 +347,7 @@
      * Execute the set of rules defined by the supplied rule set name. This method is safe to be concurrently called by multiple
      * threads, and is properly synchronized with the methods to {@link #addRuleSet(RuleSet) add},
      * {@link #updateRuleSet(RuleSet) update}, and {@link #removeRuleSet(String) remove} rule sets.
+     * 
      * @param ruleSetName the {@link RuleSet#getName() name} of the {@link RuleSet} that should be used
      * @param globals the global variables
      * @param facts the facts
@@ -396,8 +416,13 @@
         return this.shutdownLatch.await(timeout, unit);
     }
 
+    protected boolean isTerminated() {
+        return this.shutdownLatch.getCount() == 0;
+    }
+
     /**
      * Finds the JSR-94 service provider instance and returns it. If it could not be found, this method attempts to load it.
+     * 
      * @param ruleSet the rule set for which the service provider is to be found; may not be null
      * @return the rule service provider; never null
      * @throws ConfigurationException if there is a problem loading the service provider
@@ -433,6 +458,7 @@
     /**
      * Deregister the supplied rule set, if it could be found. This method does nothing if any of the service provider components
      * could not be found.
+     * 
      * @param ruleSet the rule set to be deregistered; may not be null
      * @return the service provider reference, or null if the service provider could not be found ...
      * @throws ConfigurationException

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencingService.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencingService.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/sequencers/SequencingService.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -66,18 +66,21 @@
 /**
  * A sequencing system is used to monitor changes in the content of {@link Repository JCR repositories} and to sequence the
  * content to extract or to generate structured information.
+ * 
  * @author Randall Hauch
  */
 public class SequencingService implements AdministeredService, NodeChangeListener {
 
     /**
      * Interface used to select the set of {@link Sequencer} instances that should be run.
+     * 
      * @author Randall Hauch
      */
     public static interface Selector {
 
         /**
          * Select the sequencers that should be used to sequence the supplied node.
+         * 
          * @param sequencers the list of all sequencers available at the moment; never null
          * @param node the node to be sequenced; never null
          * @param nodeChange the set of node changes; never null
@@ -89,6 +92,7 @@
     /**
      * The default {@link Selector} implementation that selects every sequencer every time it's called, regardless of the node (or
      * logger) supplied.
+     * 
      * @author Randall Hauch
      */
     protected static class DefaultSelector implements Selector {
@@ -100,12 +104,14 @@
 
     /**
      * Interface used to determine whether a {@link NodeChange} should be processed.
+     * 
      * @author Randall Hauch
      */
     public static interface NodeFilter {
 
         /**
          * Determine whether the node represented by the supplied change should be submitted for sequencing.
+         * 
          * @param nodeChange the node change event
          * @return true if the node should be submitted for sequencing, or false if the change should be ignored
          */
@@ -114,6 +120,7 @@
 
     /**
      * The default filter implementation, which accepts only new nodes or nodes that have new or changed properties.
+     * 
      * @author Randall Hauch
      */
     protected static class DefaultNodeFilter implements NodeFilter {
@@ -126,11 +133,13 @@
 
     /**
      * The default {@link Selector} that considers every {@link Sequencer} to be used for every node.
+     * 
      * @see SequencingService#setSequencerSelector(org.jboss.dna.repository.sequencers.SequencingService.Selector)
      */
     public static final Selector DEFAULT_SEQUENCER_SELECTOR = new DefaultSelector();
     /**
      * The default {@link NodeFilter} that accepts new nodes or nodes that have new/changed properties.
+     * 
      * @see SequencingService#setSequencerSelector(org.jboss.dna.repository.sequencers.SequencingService.Selector)
      */
     public static final NodeFilter DEFAULT_NODE_FILTER = new DefaultNodeFilter();
@@ -144,6 +153,7 @@
 
     /**
      * The administrative component for this service.
+     * 
      * @author Randall Hauch
      */
     protected class Administrator extends AbstractServiceAdministrator {
@@ -173,6 +183,14 @@
         /**
          * {@inheritDoc}
          */
+        @Override
+        protected boolean doCheckIsTerminated() {
+            return isServiceTerminated();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
         public boolean awaitTermination( long timeout, TimeUnit unit ) throws InterruptedException {
             return doAwaitTermination(timeout, unit);
         }
@@ -199,6 +217,7 @@
 
     /**
      * Return the administrative component for this service.
+     * 
      * @return the administrative component; never null
      */
     public ServiceAdministrator getAdministrator() {
@@ -207,6 +226,7 @@
 
     /**
      * Get the statistics for this system.
+     * 
      * @return statistics
      */
     public Statistics getStatistics() {
@@ -224,6 +244,7 @@
      * Get the class loader factory that should be used to load sequencers. By default, this service uses a factory that will
      * return either the {@link Thread#getContextClassLoader() current thread's context class loader} (if not null) or the class
      * loader that loaded this class.
+     * 
      * @return the class loader factory; never null
      * @see #setClassLoaderFactory(ClassLoaderFactory)
      */
@@ -235,6 +256,7 @@
      * Set the Maven Repository that should be used to load the sequencer classes. By default, this service uses a class loader
      * factory that will return either the {@link Thread#getContextClassLoader() current thread's context class loader} (if not
      * null) or the class loader that loaded this class.
+     * 
      * @param classLoaderFactory the class loader factory reference, or null if the default class loader factory should be used.
      * @see #getClassLoaderFactory()
      */
@@ -245,6 +267,7 @@
     /**
      * Add the configuration for a sequencer, or update any existing one that represents the
      * {@link SequencerConfig#equals(Object) same configuration}
+     * 
      * @param config the new configuration
      * @return true if the sequencer was added, or false if there already was an existing and
      * {@link SequencerConfig#hasChanged(SequencerConfig) unchanged} sequencer configuration
@@ -259,6 +282,7 @@
     /**
      * Update the configuration for a sequencer, or add it if there is no
      * {@link SequencerConfig#equals(Object) matching configuration}.
+     * 
      * @param config the updated (or new) configuration
      * @return true if the sequencer was updated, or false if there already was an existing and
      * {@link SequencerConfig#hasChanged(SequencerConfig) unchanged} sequencer configuration
@@ -272,6 +296,7 @@
 
     /**
      * Remove the configuration for a sequencer.
+     * 
      * @param config the configuration to be removed
      * @return true if the sequencer was removed, or false if there was no existing sequencer
      * @throws IllegalArgumentException if <code>config</code> is null
@@ -284,6 +309,7 @@
 
     /**
      * Get the logger for this system
+     * 
      * @return the logger
      */
     public Logger getLogger() {
@@ -292,6 +318,7 @@
 
     /**
      * Set the logger for this system.
+     * 
      * @param logger the logger, or null if the standard logging should be used
      */
     public void setLogger( Logger logger ) {
@@ -318,6 +345,7 @@
 
     /**
      * Get the executor service used to run the sequencers.
+     * 
      * @return the executor service
      * @see #setExecutorService(ExecutorService)
      */
@@ -328,6 +356,7 @@
     /**
      * Set the executor service that should be used by this system. By default, the system is set up with a
      * {@link Executors#newSingleThreadExecutor() executor that uses a single thread}.
+     * 
      * @param executorService the executor service
      * @see #getExecutorService()
      * @see Executors#newCachedThreadPool()
@@ -355,6 +384,7 @@
      * <p>
      * This method creates a {@link Executors#newSingleThreadExecutor() single-threaded executor}.
      * </p>
+     * 
      * @return
      */
     protected ExecutorService createDefaultExecutorService() {
@@ -380,6 +410,13 @@
         }
     }
 
+    protected boolean isServiceTerminated() {
+        if (this.executorService != null) {
+            return this.executorService.isTerminated();
+        }
+        return true;
+    }
+
     protected boolean doAwaitTermination( long timeout, TimeUnit unit ) throws InterruptedException {
         if (this.executorService == null || this.executorService.isTerminated()) return true;
         return this.executorService.awaitTermination(timeout, unit);
@@ -387,6 +424,7 @@
 
     /**
      * Get the sequencing selector used by this system.
+     * 
      * @return the sequencing selector
      */
     public Selector getSequencerSelector() {
@@ -395,6 +433,7 @@
 
     /**
      * Set the sequencer selector, or null if the {@link #DEFAULT_SEQUENCER_SELECTOR default sequencer selector} should be used.
+     * 
      * @param sequencerSelector the selector
      */
     public void setSequencerSelector( Selector sequencerSelector ) {
@@ -403,6 +442,7 @@
 
     /**
      * Get the node filter used by this system.
+     * 
      * @return the node filter
      */
     public NodeFilter getNodeFilter() {
@@ -412,6 +452,7 @@
     /**
      * Set the filter that checks which nodes are to be sequenced, or null if the {@link #DEFAULT_NODE_FILTER default node filter}
      * should be used.
+     * 
      * @param nodeFilter the new node filter
      */
     public void setNodeFilter( NodeFilter nodeFilter ) {
@@ -443,6 +484,7 @@
     /**
      * Do the work of processing by sequencing the node. This method is called by the {@link #executorService executor service}
      * when it performs it's work on the enqueued {@link ChangedNode ChangedNode runnable objects}.
+     * 
      * @param node the node to be processed.
      */
     protected void processChangedNode( NodeChange changedNode ) {
@@ -620,6 +662,7 @@
 
     /**
      * The statistics for the system. Each sequencing system has an instance of this class that is updated.
+     * 
      * @author Randall Hauch
      */
     @ThreadSafe

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AbstractServiceAdministrator.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AbstractServiceAdministrator.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/AbstractServiceAdministrator.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -30,6 +30,7 @@
 /**
  * Simple abstract implementation of the service administrator interface that can be easily subclassed by services that require an
  * administrative interface.
+ * 
  * @author Randall Hauch
  */
 @ThreadSafe
@@ -47,6 +48,7 @@
 
     /**
      * Return the current state of this service.
+     * 
      * @return the current state
      */
     public State getState() {
@@ -55,6 +57,7 @@
 
     /**
      * Set the state of the service. This method does nothing if the desired state matches the current state.
+     * 
      * @param state the desired state
      * @return this object for method chaining purposes
      * @see #setState(String)
@@ -72,6 +75,7 @@
                 pause();
                 break;
             case SHUTDOWN:
+            case TERMINATED:
                 shutdown();
                 break;
         }
@@ -80,6 +84,7 @@
 
     /**
      * Set the state of the service. This method does nothing if the desired state matches the current state.
+     * 
      * @param state the desired state in string form
      * @return this object for method chaining purposes
      * @throws IllegalArgumentException if the specified state string is null or does not match one of the predefined
@@ -100,6 +105,7 @@
     /**
      * Start monitoring and sequence the events. This method can be called multiple times, including after the service is
      * {@link #pause() paused}. However, once the service is {@link #shutdown() shutdown}, it cannot be started or paused.
+     * 
      * @return this object for method chaining purposes
      * @throws IllegalStateException if called when the service has been {@link #shutdown() shutdown}.
      * @see #pause()
@@ -107,10 +113,16 @@
      * @see #isStarted()
      */
     public synchronized ServiceAdministrator start() {
-        if (isShutdown()) throw new IllegalStateException(RepositoryI18n.serviceShutdowAndMayNotBeStarted.text(getServiceName()));
-        if (this.state != State.STARTED) {
-            doStart(this.state);
-            this.state = State.STARTED;
+        switch (this.state) {
+            case STARTED:
+                break;
+            case PAUSED:
+                doStart(this.state);
+                this.state = State.STARTED;
+                break;
+            case SHUTDOWN:
+            case TERMINATED:
+                throw new IllegalStateException(RepositoryI18n.serviceShutdowAndMayNotBeStarted.text(getServiceName()));
         }
         return this;
     }
@@ -119,6 +131,7 @@
      * Implementation of the functionality to switch to the started state. This method is only called if the state from which the
      * service is transitioning is appropriate ({@link State#PAUSED}). This method does nothing by default, and should be
      * overridden if needed.
+     * 
      * @param fromState the state from which this service is transitioning; never null
      * @throws IllegalStateException if the service is such that it cannot be transitioned from the supplied state
      */
@@ -129,6 +142,7 @@
     /**
      * Temporarily stop monitoring and sequencing events. This method can be called multiple times, including after the service is
      * {@link #start() started}. However, once the service is {@link #shutdown() shutdown}, it cannot be started or paused.
+     * 
      * @return this object for method chaining purposes
      * @throws IllegalStateException if called when the service has been {@link #shutdown() shutdown}.
      * @see #start()
@@ -136,10 +150,16 @@
      * @see #isPaused()
      */
     public synchronized ServiceAdministrator pause() {
-        if (isShutdown()) throw new IllegalStateException(RepositoryI18n.serviceShutdowAndMayNotBePaused.text(getServiceName()));
-        if (this.state != State.PAUSED) {
-            doPause(this.state);
-            this.state = State.PAUSED;
+        switch (this.state) {
+            case STARTED:
+                doPause(this.state);
+                this.state = State.PAUSED;
+                break;
+            case PAUSED:
+                break;
+            case SHUTDOWN:
+            case TERMINATED:
+                throw new IllegalStateException(RepositoryI18n.serviceShutdowAndMayNotBePaused.text(getServiceName()));
         }
         return this;
     }
@@ -148,6 +168,7 @@
      * Implementation of the functionality to switch to the paused state. This method is only called if the state from which the
      * service is transitioning is appropriate ({@link State#STARTED}). This method does nothing by default, and should be
      * overridden if needed.
+     * 
      * @param fromState the state from which this service is transitioning; never null
      * @throws IllegalStateException if the service is such that it cannot be transitioned from the supplied state
      */
@@ -158,15 +179,24 @@
     /**
      * Permanently stop monitoring and sequencing events. This method can be called multiple times, but only the first call has an
      * effect. Once the service has been shutdown, it may not be {@link #start() restarted} or {@link #pause() paused}.
+     * 
      * @return this object for method chaining purposes
      * @see #start()
      * @see #pause()
      * @see #isShutdown()
      */
     public synchronized ServiceAdministrator shutdown() {
-        if (this.state != State.SHUTDOWN) {
-            doShutdown(this.state);
-            this.state = State.SHUTDOWN;
+        switch (this.state) {
+            case STARTED:
+            case PAUSED:
+                this.state = State.SHUTDOWN;
+                doShutdown(this.state);
+                isTerminated();
+                break;
+            case SHUTDOWN:
+            case TERMINATED:
+                isTerminated();
+                break;
         }
         return this;
     }
@@ -175,6 +205,7 @@
      * Implementation of the functionality to switch to the shutdown state. This method is only called if the state from which the
      * service is transitioning is appropriate ({@link State#STARTED} or {@link State#PAUSED}). This method does nothing by
      * default, and should be overridden if needed.
+     * 
      * @param fromState the state from which this service is transitioning; never null
      * @throws IllegalStateException if the service is such that it cannot be transitioned from the supplied state
      */
@@ -184,6 +215,7 @@
 
     /**
      * Return whether this service has been started and is currently running.
+     * 
      * @return true if started and currently running, or false otherwise
      * @see #start()
      * @see #pause()
@@ -196,6 +228,7 @@
 
     /**
      * Return whether this service is currently paused.
+     * 
      * @return true if currently paused, or false otherwise
      * @see #pause()
      * @see #start()
@@ -208,17 +241,45 @@
 
     /**
      * Return whether this service is stopped and unable to be restarted.
+     * 
      * @return true if currently shutdown, or false otherwise
      * @see #shutdown()
      * @see #isPaused()
      * @see #isStarted()
      */
     public boolean isShutdown() {
-        return this.state == State.SHUTDOWN;
+        return this.state == State.SHUTDOWN || this.state == State.TERMINATED;
     }
 
     /**
+     * {@inheritDoc}
+     */
+    public boolean isTerminated() {
+        switch (this.state) {
+            case PAUSED:
+            case STARTED:
+            case SHUTDOWN:
+                if (doCheckIsTerminated()) {
+                    this.state = State.TERMINATED;
+                    return true;
+                }
+                return false;
+            case TERMINATED:
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Subclasses should implement this method to determine whether the service has completed shutdown.
+     * 
+     * @return true if terminated, or false otherwise
+     */
+    protected abstract boolean doCheckIsTerminated();
+
+    /**
      * Get the name of this service in the current locale.
+     * 
      * @return the service name
      */
     public String getServiceName() {
@@ -227,10 +288,12 @@
 
     /**
      * Get the name of this service in the specified locale.
+     * 
      * @param locale the locale in which the service name is to be returned; may be null if the default locale is to be used
      * @return the service name
      */
     public String getServiceName( Locale locale ) {
         return this.serviceName.text(locale);
     }
+
 }

Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/ServiceAdministrator.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/ServiceAdministrator.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/services/ServiceAdministrator.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -26,6 +26,7 @@
 
 /**
  * Contract defining an administrative interface for controlling the running state of a service.
+ * 
  * @author Randall Hauch
  */
 @ThreadSafe
@@ -33,22 +34,26 @@
 
     /**
      * The available states.
+     * 
      * @author Randall Hauch
      */
     public static enum State {
         STARTED,
         PAUSED,
-        SHUTDOWN;
+        SHUTDOWN,
+        TERMINATED;
     }
 
     /**
      * Return the current state of this system.
+     * 
      * @return the current state
      */
     public State getState();
 
     /**
      * Set the state of the system. This method does nothing if the desired state matches the current state.
+     * 
      * @param state the desired state
      * @return this object for method chaining purposes
      * @see #setState(String)
@@ -60,6 +65,7 @@
 
     /**
      * Set the state of the system. This method does nothing if the desired state matches the current state.
+     * 
      * @param state the desired state in string form
      * @return this object for method chaining purposes
      * @throws IllegalArgumentException if the specified state string is null or does not match one of the predefined
@@ -74,6 +80,7 @@
     /**
      * Start monitoring and sequence the events. This method can be called multiple times, including after the system is
      * {@link #pause() paused}. However, once the system is {@link #shutdown() shutdown}, it cannot be started or paused.
+     * 
      * @return this object for method chaining purposes
      * @throws IllegalStateException if called when the system has been {@link #shutdown() shutdown}.
      * @see #pause()
@@ -85,6 +92,7 @@
     /**
      * Temporarily stop monitoring and sequencing events. This method can be called multiple times, including after the system is
      * {@link #start() started}. However, once the system is {@link #shutdown() shutdown}, it cannot be started or paused.
+     * 
      * @return this object for method chaining purposes
      * @throws IllegalStateException if called when the system has been {@link #shutdown() shutdown}.
      * @see #start()
@@ -96,6 +104,7 @@
     /**
      * Permanently stop monitoring and sequencing events. This method can be called multiple times, but only the first call has an
      * effect. Once the system has been shutdown, it may not be {@link #start() restarted} or {@link #pause() paused}.
+     * 
      * @return this object for method chaining purposes
      * @see #start()
      * @see #pause()
@@ -104,41 +113,62 @@
     public ServiceAdministrator shutdown();
 
     /**
-     * Blocks until all work has completed execution after a shutdown request, or the timeout occurs, or the current thread is
-     * interrupted, whichever happens first.
+     * Blocks until the shutdown has completed, or the timeout occurs, or the current thread is interrupted, whichever happens
+     * first.
+     * 
      * @param timeout the maximum time to wait
      * @param unit the time unit of the timeout argument
-     * @return <tt>true</tt> if this service terminated and <tt>false</tt> if the timeout elapsed before termination
+     * @return <tt>true</tt> if this service complete shut down and <tt>false</tt> if the timeout elapsed before it was shut
+     * down completely
      * @throws InterruptedException if interrupted while waiting
      */
     boolean awaitTermination( long timeout, TimeUnit unit ) throws InterruptedException;
 
     /**
      * Return whether this system has been started and is currently running.
+     * 
      * @return true if started and currently running, or false otherwise
      * @see #start()
      * @see #pause()
      * @see #isPaused()
      * @see #isShutdown()
+     * @see #isTerminated()
      */
     public boolean isStarted();
 
     /**
      * Return whether this system is currently paused.
+     * 
      * @return true if currently paused, or false otherwise
      * @see #pause()
      * @see #start()
      * @see #isStarted()
      * @see #isShutdown()
+     * @see #isTerminated()
      */
     public boolean isPaused();
 
     /**
-     * Return whether this system is stopped and unable to be restarted.
-     * @return true if currently shutdown, or false otherwise
+     * Return whether this system has been shut down.
+     * 
+     * @return true if this service has been shut down, or false otherwise
      * @see #shutdown()
      * @see #isPaused()
      * @see #isStarted()
+     * @see #isTerminated()
      */
     public boolean isShutdown();
+
+    /**
+     * Return whether this system has finished {@link #shutdown() shutting down}. Note that <code>isTerminated</code> is never
+     * <code>true</code> unless either {@link #shutdown()} was called first.
+     * 
+     * @return true if the system has finished shutting down, or false otherwise
+     * @see #shutdown()
+     * @see #isPaused()
+     * @see #isStarted()
+     * @see #isShutdown()
+     */
+    public boolean isTerminated();
+
 }

Modified: trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
===================================================================
--- trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties	2008-06-10 20:19:15 UTC (rev 253)
@@ -22,6 +22,7 @@
 invalidStateString = Invalid state parameter "{0}"
 serviceShutdowAndMayNotBeStarted = The {0} has been shutdown and may not be (re)started
 serviceShutdowAndMayNotBePaused = The {0} has been shutdown and my not be paused
+serviceNotShutdowAndMayNotBeTerminated = The {0} has not been shutdown and may not be terminated
 unableToFindRepositoryInJndi = Unable to find a JCR repository in JNDI at "{0}"
 unableToRegisterRepositoryInJndi = Unable to register a JCR repository in JNDI at "{0}"
 unableToUnregisterRepositoryInJndi = Unable to unregister a JCR repository at JNDI at "{0}"

Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -105,6 +105,24 @@
     }
 
     @Test
+    public void shouldReturnImmediatelyWhenExecutingNullOrEmptyCommandArray() {
+        stub(repositoryAdmin.isStarted()).toReturn(true);
+        ExecutionEnvironment env = mock(ExecutionEnvironment.class);
+        connection.execute(env, (GraphCommand[])null);
+        verify(repositoryAdmin, times(1)).isStarted();
+        connection.execute(env, new GraphCommand[0]);
+        verify(repositoryAdmin, times(2)).isStarted();
+    }
+
+    @Test
+    public void shouldSkipNullCommandReferencesWhenExecuting() {
+        stub(repositoryAdmin.isStarted()).toReturn(true);
+        ExecutionEnvironment env = mock(ExecutionEnvironment.class);
+        connection.execute(env, new GraphCommand[] {null, null, null});
+        verify(repositoryAdmin, times(1)).isStarted();
+    }
+
+    @Test
     public void shouldAddListenerToRepositoryWhenSetOnConnection() {
         // Old listener is no-op, so it is not removed from repository ...
         RepositorySourceListener listener = mock(RepositorySourceListener.class);
@@ -129,5 +147,4 @@
         connection.close();
         verify(repository, times(1)).removeListener(listener2);
     }
-
 }

Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryTest.java	                        (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryTest.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -0,0 +1,222 @@
+/*
+ * 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.repository.federation;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+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 java.util.concurrent.TimeUnit;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+import org.jboss.dna.spi.graph.connection.TimeDelayingRepositorySource;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederatedRepositoryTest {
+
+    private FederatedRepository repository;
+    private String name;
+    @Mock
+    private FederationService service;
+    @Mock
+    private RepositorySourceListener listener1;
+    @Mock
+    private RepositorySourceListener listener2;
+    @Mock
+    private FederatedSource source1;
+    @Mock
+    private FederatedSource source2;
+
+    // private RepositoryConnectionPool connectionPool;
+
+    @Before
+    public void beforeEach() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        name = "Test repository";
+        repository = new FederatedRepository(service, name);
+        stub(source1.getName()).toReturn("soure 1");
+        stub(source2.getName()).toReturn("soure 2");
+    }
+
+    @Test
+    public void shouldHaveNamePassedIntoConstructor() {
+        assertThat(repository.getName(), is(name));
+    }
+
+    @Test
+    public void shouldHaveFederationServicePassedIntoConstructor() {
+        assertThat(repository.getService(), is(sameInstance(service)));
+    }
+
+    @Test
+    public void shouldHaveAdministrator() {
+        assertThat(repository.getAdministrator(), is(notNullValue()));
+    }
+
+    @Test
+    public void shouldHaveNoListenersUponCreation() {
+        assertThat(repository.getListeners(), is(notNullValue()));
+        assertThat(repository.getListeners().isEmpty(), is(true));
+    }
+
+    @Test
+    public void shouldNotAddNullListener() {
+        assertThat(repository.addListener(null), is(false));
+    }
+
+    @Test
+    public void shouldNotAddListenerIfAlreadyInList() {
+        assertThat(repository.getListeners().size(), is(0));
+        assertThat(repository.addListener(listener1), is(true));
+        assertThat(repository.getListeners().size(), is(1));
+        assertThat(repository.addListener(listener1), is(false));
+        assertThat(repository.getListeners().size(), is(1));
+    }
+
+    @Test
+    public void shouldAddDifferentListeners() {
+        assertThat(repository.getListeners().size(), is(0));
+        assertThat(repository.addListener(listener1), is(true));
+        assertThat(repository.getListeners().size(), is(1));
+        assertThat(repository.addListener(listener2), is(true));
+        assertThat(repository.getListeners().size(), is(2));
+        assertThat(repository.getListeners(), hasItems(listener1, listener2));
+        assertThat(repository.getListeners().get(0), is(sameInstance(listener1)));
+        assertThat(repository.getListeners().get(1), is(sameInstance(listener2)));
+    }
+
+    @Test
+    public void shouldAllowReorderingOfListeners() {
+        assertThat(repository.getListeners().size(), is(0));
+        assertThat(repository.addListener(listener1), is(true));
+        assertThat(repository.addListener(listener2), is(true));
+        assertThat(repository.getListeners().size(), is(2));
+        assertThat(repository.getListeners(), hasItems(listener1, listener2));
+        repository.getListeners().remove(0);
+        repository.getListeners().add(1, listener1);
+        assertThat(repository.getListeners(), hasItems(listener2, listener1));
+        assertThat(repository.getListeners().get(0), is(sameInstance(listener2)));
+        assertThat(repository.getListeners().get(1), is(sameInstance(listener1)));
+    }
+
+    @Test
+    public void shouldAllowRemovalOfListeners() {
+        assertThat(repository.getListeners().size(), is(0));
+        assertThat(repository.addListener(listener1), is(true));
+        assertThat(repository.addListener(listener2), is(true));
+        assertThat(repository.getListeners(), hasItems(listener1, listener2));
+        assertThat(repository.removeListener(listener1), is(true));
+        assertThat(repository.getListeners(), hasItems(listener2));
+        assertThat(repository.removeListener(listener2), is(true));
+        assertThat(repository.getListeners(), hasItems(new RepositorySourceListener[] {}));
+    }
+
+    @Test
+    public void shouldNotRemoveListenerThatIsNotAlreadyRegistered() {
+        assertThat(repository.getListeners().size(), is(0));
+        assertThat(repository.addListener(listener1), is(true));
+        assertThat(repository.getListeners().size(), is(1));
+        assertThat(repository.removeListener(listener2), is(false));
+    }
+
+    @Test
+    public void shouldHaveNoSourcesAfterInitialization() {
+        assertThat(repository.getSources(), is(notNullValue()));
+        assertThat(repository.getSources().isEmpty(), is(true));
+    }
+
+    @Test
+    public void shouldAddSourceThatIsNotAlreadyRegistered() {
+        assertThat(repository.getSources(), hasItems(new FederatedSource[] {}));
+        assertThat(repository.addSource(source1), is(true));
+        assertThat(repository.getSources(), hasItems(source1));
+        assertThat(repository.addSource(source2), is(true));
+        assertThat(repository.getSources(), hasItems(source1, source2));
+    }
+
+    @Test
+    public void shouldNotAddSourceThatIsAlreadyRegistered() {
+        String source1Name = source1.getName();
+        FederatedSource source1a = mock(FederatedSource.class);
+        stub(source1a.getName()).toReturn(source1Name);
+
+        assertThat(repository.getSources(), hasItems(new FederatedSource[] {}));
+        assertThat(repository.addSource(source1), is(true));
+        assertThat(repository.getSources(), hasItems(source1));
+        assertThat(repository.addSource(source2), is(true));
+        assertThat(repository.getSources(), hasItems(source1, source2));
+        assertThat(repository.addSource(source1a), is(false));
+        assertThat(repository.getSources(), hasItems(source1, source2));
+    }
+
+    @Test
+    public void shouldShutdownAndRemoveRepositoryFromFederationService() {
+        repository.getAdministrator().shutdown();
+        verify(service, times(1)).removeRepository(repository);
+    }
+
+    @Test
+    public void shouldShutdownAllSourceConnectionPoolsWhenShuttingDownRepository() throws Exception {
+        // Create the source instances that wait during termination ...
+        TimeDelayingRepositorySource timeDelaySource1 = new TimeDelayingRepositorySource("time delay source 1");
+        source1 = new FederatedSource(timeDelaySource1);
+        TimeDelayingRepositorySource timeDelaySource2 = new TimeDelayingRepositorySource("time delay source 2");
+        source2 = new FederatedSource(timeDelaySource2);
+        repository.addSource(source1);
+        repository.addSource(source2);
+        assertThat(repository.getSources(), hasItems(source1, source2));
+
+        // Get a connection from one source ...
+        RepositoryConnection connection = source2.getConnection();
+        assertThat(connection, is(notNullValue()));
+
+        // Shut down the repository, which will shut down each of the sources ...
+        repository.getAdministrator().shutdown();
+        assertThat(repository.getAdministrator().isShutdown(), is(true));
+        assertThat(repository.getAdministrator().isTerminated(), is(false));
+
+        // Source 1 should be shut down AND terminated ...
+        assertThat(source1.getConnectionPool().isShutdown(), is(true));
+        assertThat(source1.getConnectionPool().isTerminated(), is(true));
+
+        // Source 2 should be shutdown but not terminated, since we still have a connection ...
+        assertThat(source2.getConnectionPool().isShutdown(), is(true));
+        assertThat(source2.getConnectionPool().isTerminated(), is(false));
+
+        // Close the connection ...
+        connection.close();
+        assertThat(repository.getAdministrator().awaitTermination(1, TimeUnit.SECONDS), is(true));
+        assertThat(repository.getAdministrator().isShutdown(), is(true));
+        assertThat(repository.getAdministrator().isTerminated(), is(true));
+    }
+}


Property changes on: trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryTest.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencingServiceTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencingServiceTest.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/sequencers/SequencingServiceTest.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -141,7 +141,8 @@
             assertThat(sequencingService.getAdministrator().shutdown().isShutdown(), is(true));
             assertThat(sequencingService.getAdministrator().isPaused(), is(false));
             assertThat(sequencingService.getAdministrator().isStarted(), is(false));
-            assertThat(sequencingService.getAdministrator().getState(), is(ServiceAdministrator.State.SHUTDOWN));
+            ServiceAdministrator.State actualState = sequencingService.getAdministrator().getState();
+            assertThat(actualState == ServiceAdministrator.State.SHUTDOWN || actualState == ServiceAdministrator.State.TERMINATED, is(true));
         }
     }
 
@@ -170,7 +171,8 @@
         assertThat(sequencingService.getAdministrator().shutdown().isShutdown(), is(true));
         assertThat(sequencingService.getAdministrator().isPaused(), is(false));
         assertThat(sequencingService.getAdministrator().isStarted(), is(false));
-        assertThat(sequencingService.getAdministrator().getState(), is(ServiceAdministrator.State.SHUTDOWN));
+        ServiceAdministrator.State actualState = sequencingService.getAdministrator().getState();
+        assertThat(actualState == ServiceAdministrator.State.SHUTDOWN || actualState == ServiceAdministrator.State.TERMINATED, is(true));
 
         // Now start it back up ... this will fail
         sequencingService.getAdministrator().start();

Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/JndiSessionFactoryTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/JndiSessionFactoryTest.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/util/JndiSessionFactoryTest.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -27,6 +27,7 @@
 import static org.hamcrest.core.IsSame.sameInstance;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
 import javax.jcr.Repository;
 import javax.jcr.Session;
 import javax.naming.InitialContext;
@@ -34,8 +35,6 @@
 import org.jboss.dna.common.SystemFailureException;
 import org.jboss.dna.common.jcr.AbstractJcrRepositoryTest;
 import org.jboss.dna.common.naming.MockInitialContext;
-import org.jboss.dna.repository.util.JndiSessionFactory;
-import org.jmock.Mockery;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -49,14 +48,12 @@
     public static final String MOCK_REPOSITORY_NAME_ALT = "java:jcr/unit/test/repository/2";
 
     private JndiSessionFactory factory;
-    private Mockery context;
     private Repository mockRepository;
     private Session session;
 
     @Before
     public void beforeEach() throws Exception {
-        this.context = new Mockery();
-        this.mockRepository = this.context.mock(Repository.class);
+        this.mockRepository = mock(Repository.class);
         MockInitialContext.register(MOCK_REPOSITORY_NAME, this.mockRepository);
         this.factory = new JndiSessionFactory();
     }

Modified: trunk/dna-repository/src/test/resources/log4j.properties
===================================================================
--- trunk/dna-repository/src/test/resources/log4j.properties	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-repository/src/test/resources/log4j.properties	2008-06-10 20:19:15 UTC (rev 253)
@@ -9,7 +9,9 @@
 
 # Set up the default logging to be INFO level, then override specific units
 log4j.logger.org.jboss.dna=INFO
-log4j.logger.org.jboss.dna.repository.sequencers=TRACE
+#log4j.logger.org.jboss.dna.repository.sequencers=TRACE
+#log4j.logger.org.jboss.dna.repository.federation=DEBUG
+#log4j.logger.org.jboss.dna.spi=DEBUG
 
 # Jackrabbit logging
 log4j.logger.org.apache.jackrabbit=WARN, stdout

Modified: trunk/dna-spi/pom.xml
===================================================================
--- trunk/dna-spi/pom.xml	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/pom.xml	2008-06-10 20:19:15 UTC (rev 253)
@@ -44,15 +44,10 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.jmock</groupId>
-      <artifactId>jmock</artifactId>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.jmock</groupId>
-      <artifactId>jmock-junit4</artifactId>
-      <scope>test</scope>
-    </dependency>
     <!-- 
     Logging (require SLF4J API for compiling, but use Log4J and its SLF4J binding for testing) 
     -->

Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -21,14 +21,11 @@
  */
 package org.jboss.dna.spi.graph.connection;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.Set;
 import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Callable;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -40,7 +37,6 @@
 import net.jcip.annotations.GuardedBy;
 import net.jcip.annotations.ThreadSafe;
 import org.jboss.dna.common.util.ArgCheck;
-import org.jboss.dna.common.util.LogContext;
 import org.jboss.dna.common.util.Logger;
 import org.jboss.dna.spi.SpiI18n;
 import org.jboss.dna.spi.cache.CachePolicy;
@@ -405,104 +401,6 @@
     }
 
     // -------------------------------------------------
-    // Utility methods ...
-    // -------------------------------------------------
-
-    /**
-     * Call the supplied operation, using a connection from this pool.
-     * 
-     * @param <T> the return type for the operation
-     * @param operation the operation to be run using a connection in this pool
-     * @return the results from the operation
-     * @throws RepositorySourceException if there was an error obtaining the new connection
-     * @throws InterruptedException if the thread was interrupted during the operation
-     * @throws IllegalArgumentException if the operation is null
-     * @see #callable(RepositoryOperation)
-     * @see #callables(Iterable)
-     * @see #callables(RepositoryOperation...)
-     */
-    public <T> T call( RepositoryOperation<T> operation ) throws RepositorySourceException, InterruptedException {
-        ArgCheck.isNotNull(operation, "repository operation");
-        // Get a connection ...
-        T result = null;
-        LogContext.set("context", operation.getName());
-        RepositoryConnection conn = this.getConnection();
-        try {
-            // And run the client with the connection ...
-            result = operation.run(conn);
-        } finally {
-            conn.close();
-        }
-        LogContext.clear();
-        return result;
-    }
-
-    /**
-     * Return a callable object that, when run, performs the supplied repository operation against a connection in this pool.
-     * 
-     * @param <T> the return type for the operation
-     * @param operation the operation to be run using a connection in this pool
-     * @return the callable
-     * @see #call(RepositoryOperation)
-     * @see #callables(Iterable)
-     * @see #callables(RepositoryOperation...)
-     */
-    public <T> Callable<T> callable( final RepositoryOperation<T> operation ) {
-        ArgCheck.isNotNull(operation, "repository operation");
-        final RepositoryConnectionPool pool = this;
-        return new Callable<T>() {
-
-            /**
-             * Execute by getting a connection from this pool, running the client, and return the connection to the pool.
-             * 
-             * @return the operation's result
-             * @throws Exception
-             */
-            public T call() throws Exception {
-                return pool.call(operation);
-            }
-        };
-    }
-
-    /**
-     * Return a collection of callable objects that, when run, perform the supplied repository operations against connections in
-     * this pool.
-     * 
-     * @param <T> the return type for the operations
-     * @param operations the operations to be run using connection from this pool
-     * @return the collection of callables
-     * @see #call(RepositoryOperation)
-     * @see #callable(RepositoryOperation)
-     * @see #callables(Iterable)
-     */
-    public <T> List<Callable<T>> callables( RepositoryOperation<T>... operations ) {
-        List<Callable<T>> callables = new ArrayList<Callable<T>>();
-        for (final RepositoryOperation<T> operation : operations) {
-            callables.add(callable(operation));
-        }
-        return callables;
-    }
-
-    /**
-     * Return a collection of callable objects that, when run, perform the supplied repository operations against connections in
-     * this pool.
-     * 
-     * @param <T> the return type for the operations
-     * @param operations the operations to be run using connection from this pool
-     * @return the collection of callables
-     * @see #call(RepositoryOperation)
-     * @see #callable(RepositoryOperation)
-     * @see #callables(RepositoryOperation...)
-     */
-    public <T> List<Callable<T>> callables( Iterable<RepositoryOperation<T>> operations ) {
-        List<Callable<T>> callables = new ArrayList<Callable<T>>();
-        for (final RepositoryOperation<T> operation : operations) {
-            callables.add(callable(operation));
-        }
-        return callables;
-    }
-
-    // -------------------------------------------------
     // State management methods ...
     // -------------------------------------------------
 
@@ -956,7 +854,7 @@
     @GuardedBy( "mainLock" )
     protected int drainUnusedConnections( int count ) {
         if (count <= 0) return 0;
-        this.logger.trace("Draining up to {} unused repository connections to {0}", count, getName());
+        this.logger.trace("Draining up to {0} unused repository connections to {1}", count, getName());
         // Drain the extra connections from those available ...
         Collection<ConnectionWrapper> extraConnections = new LinkedList<ConnectionWrapper>();
         this.availableConnections.drainTo(extraConnections, count);

Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperation.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperation.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperation.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -22,18 +22,43 @@
 package org.jboss.dna.spi.graph.connection;
 
 /**
+ * An operation that runs against a repository connection.
+ * 
  * @author Randall Hauch
  * @param <T> the type of result returned by the client
  */
 public interface RepositoryOperation<T> {
 
+    /**
+     * Get the name of this operation.
+     * 
+     * @return the operation's name
+     */
     String getName();
 
+    /**
+     * Run the operation using the supplied connection.
+     * 
+     * @param connection the connection; may not be null
+     * @return the result of the operation
+     * @throws RepositorySourceException if there is a problem with the connection
+     * @throws InterruptedException if this thread was interrupted
+     */
     T run( RepositoryConnection connection ) throws RepositorySourceException, InterruptedException;
 
+    /**
+     * A factory interface for creating repository operations.
+     * 
+     * @param <T> the type of result for the operations
+     * @author Randall Hauch
+     */
     public static interface Factory<T> {
 
+        /**
+         * Create a repository operation that returns the result of type T.
+         * 
+         * @return the operation
+         */
         RepositoryOperation<T> create();
     }
-
 }

Added: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperations.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperations.java	                        (rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperations.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -0,0 +1,155 @@
+/*
+ * 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.spi.graph.connection;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.Callable;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.LogContext;
+
+/**
+ * @author Randall Hauch
+ */
+public class RepositoryOperations {
+
+    /**
+     * Call the supplied operation, using a connection from this pool.
+     * 
+     * @param <T> the return type for the operation
+     * @param connectionFactory the factory for the connection to use
+     * @param operation the operation to be run using a new connection obtained from the factory
+     * @return the results from the operation
+     * @throws RepositorySourceException if there was an error obtaining the new connection
+     * @throws InterruptedException if the thread was interrupted during the operation
+     * @throws IllegalArgumentException if the operation is null
+     * @see #createCallable(RepositoryConnectionFactory, RepositoryOperation)
+     * @see #createCallables(RepositoryConnectionFactory, Iterable)
+     * @see #createCallables(RepositoryConnectionFactory, RepositoryOperation...)
+     */
+    public static <T> T call( RepositoryConnectionFactory connectionFactory, RepositoryOperation<T> operation ) throws RepositorySourceException, InterruptedException {
+        ArgCheck.isNotNull(operation, "repository operation");
+        // Get a connection ...
+        T result = null;
+        LogContext.set("context", operation.getName());
+        RepositoryConnection conn = connectionFactory.getConnection();
+        try {
+            // And run the client with the connection ...
+            result = operation.run(conn);
+        } finally {
+            conn.close();
+        }
+        LogContext.clear();
+        return result;
+    }
+
+    /**
+     * Return a callable object that, when run, performs the supplied repository operation against a connection obtained from the
+     * supplied factory.
+     * 
+     * @param <T> the return type for the operation
+     * @param connectionFactory the factory for the connection to use
+     * @param operation the operation to be run using a new connection obtained from the factory
+     * @return the callable
+     * @see #call(RepositoryConnectionFactory, RepositoryOperation)
+     * @see #createCallables(RepositoryConnectionFactory, Iterable)
+     * @see #createCallables(RepositoryConnectionFactory, RepositoryOperation...)
+     */
+    public static <T> Callable<T> createCallable( final RepositoryConnectionFactory connectionFactory, final RepositoryOperation<T> operation ) {
+        ArgCheck.isNotNull(operation, "repository operation");
+        return new Callable<T>() {
+
+            /**
+             * Execute by getting a connection from this pool, running the client, and return the connection to the pool.
+             * 
+             * @return the operation's result
+             * @throws Exception
+             */
+            public T call() throws Exception {
+                return RepositoryOperations.call(connectionFactory, operation);
+            }
+        };
+    }
+
+    /**
+     * Return a collection of callable objects that, when run, perform the supplied repository operations against connections in
+     * this pool.
+     * 
+     * @param <T> the return type for the operations
+     * @param connectionFactory the factory for the connection to use
+     * @param operations the operations to be run using connections from the factory
+     * @return the collection of callables
+     * @see #call(RepositoryConnectionFactory, RepositoryOperation)
+     * @see #createCallable(RepositoryConnectionFactory, RepositoryOperation)
+     * @see #createCallables(RepositoryConnectionFactory, Iterable)
+     */
+    public static <T> List<Callable<T>> createCallables( final RepositoryConnectionFactory connectionFactory, final RepositoryOperation<T>... operations ) {
+        List<Callable<T>> callables = new ArrayList<Callable<T>>();
+        for (final RepositoryOperation<T> operation : operations) {
+            callables.add(createCallable(connectionFactory, operation));
+        }
+        return callables;
+    }
+
+    /**
+     * Return a collection of callable objects that, when run, perform the supplied repository operations against connections in
+     * this pool.
+     * 
+     * @param <T> the return type for the operations
+     * @param connectionFactory the factory for the connection to use
+     * @param operations the operations to be run using connections from the factory
+     * @return the collection of callables
+     * @see #call(RepositoryConnectionFactory, RepositoryOperation)
+     * @see #createCallable(RepositoryConnectionFactory, RepositoryOperation)
+     * @see #createCallables(RepositoryConnectionFactory, RepositoryOperation...)
+     */
+    public static <T> List<Callable<T>> createCallables( final RepositoryConnectionFactory connectionFactory, Iterable<RepositoryOperation<T>> operations ) {
+        List<Callable<T>> callables = new ArrayList<Callable<T>>();
+        for (final RepositoryOperation<T> operation : operations) {
+            callables.add(createCallable(connectionFactory, operation));
+        }
+        return callables;
+    }
+
+    /**
+     * Return a collection of callable objects that, when run, perform the supplied repository operations against connections in
+     * this pool.
+     * 
+     * @param <T> the return type for the operations
+     * @param connectionFactory the factory for the connection to use
+     * @param operations the operations to be run using connections from the factory
+     * @return the collection of callables
+     * @see #call(RepositoryConnectionFactory, RepositoryOperation)
+     * @see #createCallable(RepositoryConnectionFactory, RepositoryOperation)
+     * @see #createCallables(RepositoryConnectionFactory, RepositoryOperation...)
+     */
+    public static <T> List<Callable<T>> createCallables( final RepositoryConnectionFactory connectionFactory, Iterator<RepositoryOperation<T>> operations ) {
+        List<Callable<T>> callables = new ArrayList<Callable<T>>();
+        while (operations.hasNext()) {
+            final RepositoryOperation<T> operation = operations.next();
+            callables.add(createCallable(connectionFactory, operation));
+        }
+        return callables;
+    }
+
+}


Property changes on: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperations.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Deleted: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/MockRepositorySource.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/MockRepositorySource.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/MockRepositorySource.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -1,238 +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.spi.graph.connection;
-
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
-import javax.naming.Reference;
-import javax.transaction.xa.XAResource;
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.spi.cache.CachePolicy;
-import org.jboss.dna.spi.graph.commands.GraphCommand;
-import org.jmock.Mockery;
-
-/**
- * @author Randall Hauch
- */
- at ThreadSafe
-public class MockRepositorySource implements RepositorySource {
-
-    private final String identifier;
-    private final AtomicInteger retryLimit = new AtomicInteger(0);
-    private final Mockery context;
-    private final AtomicInteger connectionsOpenedCount = new AtomicInteger(0);
-    private final AtomicInteger connectionsClosedCount = new AtomicInteger(0);
-    private final Set<Connection> openConnections = new CopyOnWriteArraySet<Connection>();
-    private CachePolicy defaultCachePolicy;
-
-    public MockRepositorySource( String identifier, Mockery context ) {
-        this.identifier = identifier;
-        this.context = context;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String getName() {
-        return this.identifier;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public int getRetryLimit() {
-        return this.retryLimit.get();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void setRetryLimit( int limit ) {
-        this.retryLimit.set(limit);
-    }
-
-    public CachePolicy getDefaultCachePolicy() {
-        return defaultCachePolicy;
-    }
-
-    public void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
-        this.defaultCachePolicy = defaultCachePolicy;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public RepositoryConnection getConnection() throws RepositorySourceException {
-        int connectionNumber = this.connectionsOpenedCount.incrementAndGet();
-        String connectionName = "Connection " + connectionNumber;
-        XAResource xaResource = context != null ? context.mock(XAResource.class, connectionName) : null;
-        Connection c = newConnection(connectionName, xaResource);
-        this.openConnections.add(c);
-        return c;
-    }
-
-    protected Connection newConnection( String connectionName, XAResource xaResource ) throws RepositorySourceException {
-        Connection c = new Connection(connectionName);
-        c.setXaResource(xaResource);
-        return c;
-    }
-
-    protected void close( Connection conn ) {
-        if (conn != null && this.openConnections.remove(conn)) {
-            this.connectionsClosedCount.incrementAndGet();
-        }
-    }
-
-    public int getOpenConnectionCount() {
-        return this.openConnections.size();
-    }
-
-    public int getTotalConnectionsCreated() {
-        return this.connectionsOpenedCount.get();
-    }
-
-    public int getTotalConnectionsClosed() {
-        return this.connectionsClosedCount.get();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public Reference getReference() {
-        throw new UnsupportedOperationException();
-    }
-
-    public class Connection implements RepositoryConnection {
-
-        private final String connectionName;
-        private final AtomicBoolean closed = new AtomicBoolean(false);
-        private final AtomicBoolean loadResponse = new AtomicBoolean(true);
-        private final AtomicBoolean pingResponse = new AtomicBoolean(true);
-        private final AtomicLong closeCount = new AtomicLong(0);
-        private final AtomicLong loadCount = new AtomicLong(0);
-        private final AtomicLong loadDelay = new AtomicLong(0);
-        private final AtomicLong pingCount = new AtomicLong(0);
-        private final AtomicLong pingDelay = new AtomicLong(0);
-        private final AtomicReference<XAResource> xaResource = new AtomicReference<XAResource>();
-
-        protected Connection( String connectionName ) {
-            assert connectionName != null && connectionName.trim().length() != 0;
-            this.connectionName = connectionName;
-        }
-
-        public String getConnectionName() {
-            return this.connectionName;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public void close() {
-            this.closeCount.incrementAndGet();
-            this.closed.set(true);
-            MockRepositorySource.this.close(this);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public String getSourceName() {
-            return MockRepositorySource.this.getName();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public CachePolicy getDefaultCachePolicy() {
-            return MockRepositorySource.this.getDefaultCachePolicy();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public XAResource getXAResource() {
-            return this.xaResource.get();
-        }
-
-        public void setXaResource( XAResource xaResource ) {
-            this.xaResource.set(xaResource);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public void execute( ExecutionEnvironment env, GraphCommand... commands ) throws RepositorySourceException, InterruptedException {
-            long delay = this.loadDelay.get();
-            if (delay > 0l) Thread.sleep(delay);
-            this.loadCount.incrementAndGet();
-        }
-
-        public void setLoadResponse( boolean response ) {
-            this.loadResponse.set(response);
-        }
-
-        public void setLoadDelay( long time, TimeUnit unit ) {
-            this.loadDelay.set(unit.toMillis(time));
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public boolean ping( long time, TimeUnit unit ) throws InterruptedException {
-            Thread.sleep(this.pingDelay.get());
-            return this.pingResponse.get();
-        }
-
-        public void setPingResponse( boolean pingResponse ) {
-            this.pingResponse.set(pingResponse);
-        }
-
-        public void setPingDelay( long time, TimeUnit unit ) {
-            this.pingDelay.set(unit.toMillis(time));
-        }
-
-        public long getPingCount() {
-            return this.pingCount.get();
-        }
-
-        public long getLoadCount() {
-            return this.loadCount.get();
-        }
-
-        public long getCloseCount() {
-            return this.closeCount.get();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public void setListener( RepositorySourceListener listener ) {
-        }
-
-    }
-
-}

Modified: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPoolTest.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPoolTest.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPoolTest.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -23,11 +23,11 @@
 
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsNull.notNullValue;
+import static org.jboss.dna.spi.graph.connection.RepositorySourceLoadHarness.runLoadTest;
 import static org.junit.Assert.assertThat;
-import static org.jboss.dna.spi.graph.connection.RepositorySourceLoadHarness.runLoadTest;
 import java.util.List;
+import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import org.jmock.Mockery;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -39,14 +39,12 @@
 public class RepositoryConnectionPoolTest {
 
     private RepositoryConnectionPool pool;
-    private MockRepositorySource repositorySource;
+    private TimeDelayingRepositorySource repositorySource;
     private ExecutionEnvironment env;
-    private Mockery context;
 
     @Before
     public void beforeEach() throws Exception {
-        this.context = new Mockery();
-        this.repositorySource = new MockRepositorySource("source 1", this.context);
+        this.repositorySource = new TimeDelayingRepositorySource("source 1");
         this.pool = new RepositoryConnectionPool(this.repositorySource, 1, 1, 100, TimeUnit.SECONDS);
         this.env = null;
     }
@@ -160,24 +158,39 @@
     public void shouldBlockClientsWhenNotEnoughConnections() throws Exception {
         int numConnectionsInPool = 1;
         int numClients = 2;
-        RepositoryOperation.Factory<Integer> operationFactory = RepositoryTestOperations.createMultipleLoadOperationFactory(env, 10);
-        runLoadTest(repositorySource, numConnectionsInPool, numClients, 4, TimeUnit.SECONDS, operationFactory);
+        RepositoryConnectionPool pool = new RepositoryConnectionPool(repositorySource);
+        pool.setCorePoolSize(numConnectionsInPool);
+        pool.setMaximumPoolSize(numConnectionsInPool);
+        RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(env, 10);
+        runLoadTest(pool, numClients, 100, TimeUnit.MILLISECONDS, operationFactory);
+        pool.shutdown();
+        pool.awaitTermination(4, TimeUnit.SECONDS);
     }
 
     @Test
     public void shouldLimitClientsToRunSequentiallyWithOneConnectionInPool() throws Exception {
         int numConnectionsInPool = 1;
         int numClients = 3;
-        RepositoryOperation.Factory<Integer> operationFactory = RepositoryTestOperations.createMultipleLoadOperationFactory(env, 10);
-        runLoadTest(repositorySource, numConnectionsInPool, numClients, 4, TimeUnit.SECONDS, operationFactory);
+        RepositoryConnectionPool pool = new RepositoryConnectionPool(repositorySource);
+        pool.setCorePoolSize(numConnectionsInPool);
+        pool.setMaximumPoolSize(numConnectionsInPool);
+        RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(env, 10);
+        runLoadTest(pool, numClients, 100, TimeUnit.MILLISECONDS, operationFactory);
+        pool.shutdown();
+        pool.awaitTermination(4, TimeUnit.SECONDS);
     }
 
     @Test
     public void shouldClientsToRunConncurrentlyWithTwoConnectionsInPool() throws Exception {
         int numConnectionsInPool = 2;
         int numClients = 10;
-        RepositoryOperation.Factory<Integer> operationFactory = RepositoryTestOperations.createMultipleLoadOperationFactory(env, 10);
-        runLoadTest(repositorySource, numConnectionsInPool, numClients, 4, TimeUnit.SECONDS, operationFactory);
+        RepositoryConnectionPool pool = new RepositoryConnectionPool(repositorySource);
+        pool.setCorePoolSize(numConnectionsInPool);
+        pool.setMaximumPoolSize(numConnectionsInPool);
+        RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(env, 10);
+        runLoadTest(pool, numClients, 100, TimeUnit.MILLISECONDS, operationFactory);
+        pool.shutdown();
+        pool.awaitTermination(4, TimeUnit.SECONDS);
     }
 
     @Ignore( "doesn't run on hudson" )
@@ -185,13 +198,19 @@
     public void shouldClientsToRunConncurrentlyWithMultipleConnectionInPool() throws Exception {
         int numConnectionsInPool = 10;
         int numClients = 50;
-        RepositoryOperation.Factory<Integer> operationFactory = RepositoryTestOperations.createMultipleLoadOperationFactory(env, 20);
-        List<Integer> results = runLoadTest(repositorySource, numConnectionsInPool, numClients, 10, TimeUnit.SECONDS, operationFactory);
+        RepositoryConnectionPool pool = new RepositoryConnectionPool(repositorySource);
+        pool.setCorePoolSize(numConnectionsInPool);
+        pool.setMaximumPoolSize(numConnectionsInPool);
+        RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(env, 20);
+        List<Future<Integer>> results = runLoadTest(pool, numClients, 200, TimeUnit.MILLISECONDS, operationFactory);
         int total = 0;
-        for (Integer integer : results) {
-            if (integer != null) total += integer;
+        for (Future<Integer> result : results) {
+            assertThat(result.isDone(), is(true));
+            if (result.isDone()) total += result.get();
         }
         assertThat(total, is(20 * numClients));
+        pool.shutdown();
+        pool.awaitTermination(4, TimeUnit.SECONDS);
     }
 
 }

Modified: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositorySourceLoadHarness.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositorySourceLoadHarness.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositorySourceLoadHarness.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -26,7 +26,6 @@
 import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -37,12 +36,21 @@
 
 /**
  * A test harness for using repository connections under load.
+ * 
  * @author Randall Hauch
  */
 public class RepositorySourceLoadHarness {
 
-    public static <T> List<T> runLoadTest( RepositoryConnectionFactory connectionFactory, int numConnectionsInPool, int numClients, long maxTime, TimeUnit maxTimeUnit,
-                                           RepositoryOperation.Factory<T> clientFactory ) throws InterruptedException, ExecutionException {
+    public static Future<Integer> execute( RepositoryConnectionFactory connectionFactory, ExecutionEnvironment env, long maxTime, TimeUnit maxTimeUnit ) throws InterruptedException {
+        int numTimes = 1;
+        int numClients = 1;
+        RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(env, numTimes);
+        List<Future<Integer>> results = runLoadTest(connectionFactory, numClients, maxTime, maxTimeUnit, operationFactory);
+        return results.get(0);
+    }
+
+    public static <T> List<Future<T>> runLoadTest( RepositoryConnectionFactory connectionFactory, int numClients, long maxTime, TimeUnit maxTimeUnit, RepositoryOperation.Factory<T> clientFactory )
+        throws InterruptedException {
         // Create the clients ...
         Collection<RepositoryOperation<T>> clients = new ArrayList<RepositoryOperation<T>>();
         for (int i = 0; i != numClients; ++i) {
@@ -50,71 +58,47 @@
         }
 
         // and run the test ...
-        return runLoadTest(connectionFactory, numConnectionsInPool, maxTime, maxTimeUnit, clients);
+        return runLoadTest(connectionFactory, maxTime, maxTimeUnit, clients);
     }
 
-    public static <T> List<T> runLoadTest( RepositoryConnectionFactory connectionFactory, int numConnectionsInPool, long maxTime, TimeUnit maxTimeUnit, RepositoryOperation<T>... clients )
-        throws InterruptedException, ExecutionException {
+    public static <T> List<Future<T>> runLoadTest( RepositoryConnectionFactory connectionFactory, long maxTime, TimeUnit maxTimeUnit, RepositoryOperation<T>... clients ) throws InterruptedException {
         // Create the client collection ...
         Collection<RepositoryOperation<T>> clientCollection = new ArrayList<RepositoryOperation<T>>();
         for (RepositoryOperation<T> client : clients) {
             if (client != null) clientCollection.add(client);
         }
         // and run the test ...
-        return runLoadTest(connectionFactory, numConnectionsInPool, maxTime, maxTimeUnit, clientCollection);
+        return runLoadTest(connectionFactory, maxTime, maxTimeUnit, clientCollection);
     }
 
-    public static <T> List<T> runLoadTest( RepositoryConnectionFactory connectionFactory, int numConnectionsInPool, long maxTime, TimeUnit maxTimeUnit, Collection<RepositoryOperation<T>> clients )
-        throws InterruptedException, ExecutionException {
+    public static <T> List<Future<T>> runLoadTest( RepositoryConnectionFactory connectionFactory, long maxTime, TimeUnit maxTimeUnit, Collection<RepositoryOperation<T>> clients )
+        throws InterruptedException {
         assert connectionFactory != null;
-        assert numConnectionsInPool > 0;
         assert clients != null;
         assert clients.size() > 0;
 
-        // Create a connection pool ...
-        final RepositoryConnectionPool connectionPool = new RepositoryConnectionPool(connectionFactory, numConnectionsInPool, numConnectionsInPool, 10, TimeUnit.SECONDS);
-
         // Create an Executor Service, using a thread factory that makes the first 'n' thread all wait for each other ...
-        final ThreadFactory threadFactory = new TestThreadFactory(clients.size(), connectionPool);
-        final ExecutorService clientPool = Executors.newFixedThreadPool(clients.size(), threadFactory);
+        ExecutorService clientPool = null;
+        if (clients.size() == 1) {
+            clientPool = Executors.newSingleThreadExecutor();
+        } else {
+            final ThreadFactory threadFactory = new TestThreadFactory(clients.size());
+            clientPool = Executors.newFixedThreadPool(clients.size(), threadFactory);
+        }
 
         try {
             // Wrap each client by a callable and by another that uses a latch ...
-            List<Callable<T>> callables = connectionPool.callables(clients);
+            List<Callable<T>> callables = RepositoryOperations.createCallables(connectionFactory, clients);
 
             // Run the tests ...
             List<Future<T>> futures = clientPool.invokeAll(callables, maxTime, maxTimeUnit);
-
-            // Whether or not all clients completed, process the results ...
-            List<T> results = new ArrayList<T>();
-            for (Future<T> future : futures) {
-                if (future.isDone() && !future.isCancelled()) {
-                    // Record the results ...
-                    results.add(future.get());
-                } else {
-                    // Record the results as null
-                    results.add(null);
-                    // Cancell any operation that is not completed
-                    future.cancel(true);
-                }
-            }
-            // Return the results ...
-            return results;
+            return futures;
         } finally {
-            try {
-                // Shut down the pool of clients ...
-                clientPool.shutdown();
-                if (!clientPool.awaitTermination(5, TimeUnit.SECONDS)) {
-                    String msg = "Unable to shutdown clients after 5 seconds";
-                    Logger.getLogger(RepositorySourceLoadHarness.class).error(MockI18n.passthrough, msg);
-                }
-            } finally {
-                // Shut down the connections ...
-                connectionPool.shutdown();
-                if (!connectionPool.awaitTermination(5, TimeUnit.SECONDS)) {
-                    String msg = "Unable to shutdown connections after 5 seconds";
-                    Logger.getLogger(RepositorySourceLoadHarness.class).error(MockI18n.passthrough, msg);
-                }
+            // Shut down the pool of clients ...
+            clientPool.shutdown();
+            if (!clientPool.awaitTermination(5, TimeUnit.SECONDS)) {
+                String msg = "Unable to shutdown clients after 5 seconds";
+                Logger.getLogger(RepositorySourceLoadHarness.class).error(MockI18n.passthrough, msg);
             }
         }
 
@@ -123,16 +107,17 @@
     /**
      * A thread factory that makes an initial set of threads wait until all of those threads are created and ready. This is useful
      * in testing to ensure that the first threads created don't get a jump start.
+     * 
      * @author Randall Hauch
      */
     protected static class TestThreadFactory implements ThreadFactory {
 
+        protected final int totalNumberOfThreads;
         protected final CountDownLatch latch;
-        protected final RepositoryConnectionPool pool;
 
-        public TestThreadFactory( int numberOfThreadsToWait, RepositoryConnectionPool pool ) {
+        public TestThreadFactory( int numberOfThreadsToWait ) {
             this.latch = new CountDownLatch(numberOfThreadsToWait);
-            this.pool = pool;
+            this.totalNumberOfThreads = numberOfThreadsToWait;
         }
 
         /**
@@ -146,20 +131,95 @@
                  */
                 @Override
                 public void run() {
-                    try {
-                        // Count down the thread count (if 0, this doesn't do anything)
-                        latch.countDown();
-                        // Wait for all threads to reach this point ...
-                        latch.await();
-                    } catch (InterruptedException e) {
-                        throw new RuntimeException(e);
+                    if (totalNumberOfThreads > 1) {
+                        // There are other threads, and we want to synchronize with them ...
+                        try {
+                            // Count down the number of threads that are to reach this point (if 0, this doesn't do anything)
+                            latch.countDown();
+                            // Wait for all threads to reach this point ...
+                            latch.await();
+                        } catch (InterruptedException e) {
+                            throw new RuntimeException(e);
+                        }
                     }
-                    // Check that the number of connections-in-use is smaller than the maximum pool size
-                    if (pool != null) assert pool.getInUseCount() <= pool.getMaximumPoolSize();
                     super.run();
                 }
             };
         }
     }
 
+    /**
+     * Return an operation factory that produces {@link RepositoryOperation} instances that each call
+     * {@link RepositoryConnection#execute(ExecutionEnvironment, org.jboss.dna.spi.graph.commands.GraphCommand...)} the supplied
+     * number of times, intermixed with random math operations and {@link Thread#yield() yielding}.
+     * 
+     * @param env the environment
+     * @param callsPerOperation the number of <code>load</code> calls per RepositoryOperation
+     * @return the factory
+     */
+    public static RepositoryOperation.Factory<Integer> createMultipleLoadOperationFactory( final ExecutionEnvironment env, final int callsPerOperation ) {
+        return new RepositoryOperation.Factory<Integer>() {
+
+            public RepositoryOperation<Integer> create() {
+                return new CallLoadMultipleTimes(env, callsPerOperation);
+            }
+        };
+    }
+
+    public static class CallLoadMultipleTimes implements RepositoryOperation<Integer> {
+
+        private final int count;
+        private final ExecutionEnvironment env;
+
+        public CallLoadMultipleTimes( ExecutionEnvironment env, int count ) {
+            Logger.getLogger(RepositorySourceLoadHarness.class).debug("Creating repository operation to call {0} times", count);
+            this.count = count;
+            this.env = env;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public String getName() {
+            return Thread.currentThread().getName() + "-CallLoadMultipleTimes";
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Integer run( RepositoryConnection connection ) throws RepositorySourceException, InterruptedException {
+            Logger.getLogger(RepositorySourceLoadHarness.class).debug("Running {0} operation", this.getClass().getSimpleName());
+            int total = count;
+            for (int i = 0; i != count; ++i) {
+                // Add two random numbers ...
+                int int1 = random(this.hashCode() ^ (int)System.nanoTime() * i);
+                if (i % 2 == 0) {
+                    Thread.yield();
+                }
+                connection.execute(env);
+                int int2 = random(this.hashCode() ^ (int)System.nanoTime() + i);
+                total += Math.min(Math.abs(Math.max(int1, int2) + int1 * int2 / 3), count);
+            }
+            Logger.getLogger(RepositorySourceLoadHarness.class).debug("Finishing {0} operation", this.getClass().getSimpleName());
+            return total < count ? total : count; // should really always return count
+        }
+    }
+
+    /**
+     * A "random-enough" number generator that is cheap and that has no synchronization issues (like some other random number
+     * generators).
+     * <p>
+     * This was taken from <a href="http://wwww.jcip.org">Java Concurrency In Practice</a> (page 253).
+     * </p>
+     * 
+     * @param seed the seed, typically based on a hash code and nanoTime
+     * @return a number that is "random enough"
+     */
+    public static int random( int seed ) {
+        seed ^= (seed << 6);
+        seed ^= (seed >>> 21);
+        seed ^= (seed << 7);
+        return seed;
+    }
+
 }

Deleted: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryTestOperations.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryTestOperations.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryTestOperations.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -1,102 +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.spi.graph.connection;
-
-import org.jboss.dna.common.util.Logger;
-
-/**
- * @author Randall Hauch
- */
-public class RepositoryTestOperations {
-
-    /**
-     * Return an operation factory that produces {@link RepositoryOperation} instances that each call
-     * {@link RepositoryConnection#execute(ExecutionEnvironment, org.jboss.dna.spi.graph.commands.GraphCommand...)} the supplied
-     * number of times, intermixed with random math operations and {@link Thread#yield() yielding}.
-     * @param env the environment
-     * @param callsPerOperation the number of <code>load</code> calls per RepositoryOperation
-     * @return the factory
-     */
-    public static RepositoryOperation.Factory<Integer> createMultipleLoadOperationFactory( final ExecutionEnvironment env, final int callsPerOperation ) {
-        return new RepositoryOperation.Factory<Integer>() {
-
-            public RepositoryOperation<Integer> create() {
-                return new CallLoadMultipleTimes(env, callsPerOperation);
-            }
-        };
-    }
-
-    public static class CallLoadMultipleTimes implements RepositoryOperation<Integer> {
-
-        private final int count;
-        private final ExecutionEnvironment env;
-
-        public CallLoadMultipleTimes( ExecutionEnvironment env, int count ) {
-            this.count = count;
-            this.env = env;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public String getName() {
-            return Thread.currentThread().getName() + "-CallLoadMultipleTimes";
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        public Integer run( RepositoryConnection connection ) throws InterruptedException {
-            Logger.getLogger(RepositoryTestOperations.class).debug("Running {} operation", this.getClass().getSimpleName());
-            int total = count;
-            for (int i = 0; i != count; ++i) {
-                // Add two random numbers ...
-                int int1 = random(this.hashCode() ^ (int)System.nanoTime() * i);
-                if (i % 2 == 0) {
-                    Thread.yield();
-                }
-                connection.execute(env);
-                int int2 = random(this.hashCode() ^ (int)System.nanoTime() + i);
-                total += Math.min(Math.abs(Math.max(int1, int2) + int1 * int2 / 3), count);
-            }
-            Logger.getLogger(RepositoryTestOperations.class).debug("Finishing {} operation", this.getClass().getSimpleName());
-            return total < count ? total : count; // should really always return count
-        }
-    }
-
-    /**
-     * A "random-enough" number generator that is cheap and that has no synchronization issues (like some other random number
-     * generators).
-     * <p>
-     * This was taken from <a href="http://wwww.jcip.org">Java Concurrency In Practice</a> (page 253).
-     * </p>
-     * @param seed the seed, typically based on a hash code and nanoTime
-     * @return a number that is "random enough"
-     */
-    public static int random( int seed ) {
-        seed ^= (seed << 6);
-        seed ^= (seed >>> 21);
-        seed ^= (seed << 7);
-        return seed;
-    }
-
-}

Copied: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/TimeDelayingRepositorySource.java (from rev 251, trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/MockRepositorySource.java)
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/TimeDelayingRepositorySource.java	                        (rev 0)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/TimeDelayingRepositorySource.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -0,0 +1,299 @@
+/*
+ * 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.spi.graph.connection;
+
+import static org.mockito.Mockito.mock;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.naming.Reference;
+import javax.transaction.xa.XAResource;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+
+/**
+ * @author Randall Hauch
+ */
+ at ThreadSafe
+public class TimeDelayingRepositorySource implements RepositorySource {
+
+    private final String identifier;
+    private final AtomicInteger retryLimit = new AtomicInteger(0);
+    private final AtomicInteger connectionsOpenedCount = new AtomicInteger(0);
+    private final AtomicInteger connectionsClosedCount = new AtomicInteger(0);
+    private final Set<Connection> openConnections = new CopyOnWriteArraySet<Connection>();
+    private final AtomicLong loadCount = new AtomicLong(0);
+    private final AtomicLong loadDelay = new AtomicLong(0);
+    private final AtomicLong pingCount = new AtomicLong(0);
+    private final AtomicLong pingDelay = new AtomicLong(0);
+    private CachePolicy defaultCachePolicy;
+
+    public TimeDelayingRepositorySource( String identifier ) {
+        this.identifier = identifier;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName() {
+        return this.identifier;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getRetryLimit() {
+        return this.retryLimit.get();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRetryLimit( int limit ) {
+        this.retryLimit.set(limit);
+    }
+
+    public CachePolicy getDefaultCachePolicy() {
+        return defaultCachePolicy;
+    }
+
+    public void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
+        this.defaultCachePolicy = defaultCachePolicy;
+    }
+
+    /**
+     * @return loadCount
+     */
+    public long getTotalExecuteCount() {
+        return this.loadCount.get();
+    }
+
+    /**
+     * @return pingCount
+     */
+    public long getTotalPingCount() {
+        return this.pingCount.get();
+    }
+
+    /**
+     * @return loadDelay
+     */
+    public long getConnectionExecuteDelayInMillis() {
+        return this.loadDelay.get();
+    }
+
+    public void setConnectionExecuteDelay( long time, TimeUnit unit ) {
+        this.loadDelay.set(unit.toMillis(time));
+    }
+
+    /**
+     * @return pingDelay
+     */
+    public long getConnectionPingDelayInMillis() {
+        return this.pingDelay.get();
+    }
+
+    public void setConnectionPingDelay( long time, TimeUnit unit ) {
+        this.pingDelay.set(unit.toMillis(time));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public RepositoryConnection getConnection() throws RepositorySourceException {
+        int connectionNumber = this.connectionsOpenedCount.incrementAndGet();
+        String connectionName = "Connection " + connectionNumber;
+        XAResource xaResource = newXaResource(connectionName);
+        Connection c = newConnection(connectionName, xaResource);
+        this.openConnections.add(c);
+        return c;
+    }
+
+    /**
+     * Factory method that can be overridden by subclasses. This method implementation simply creates a mock {@link XAResource}.
+     * 
+     * @param connectionName the name of the connection
+     * @return the XAResource, or null if this source does not support XA
+     */
+    protected XAResource newXaResource( String connectionName ) {
+        return mock(XAResource.class);
+    }
+
+    /**
+     * Factory method that can be overridden by subclasses. This method implementation creates a new {@link Connection} that uses
+     * standard bean properties for the various delays and counts.
+     * 
+     * @param connectionName
+     * @param xaResource
+     * @return
+     * @throws RepositorySourceException
+     */
+    protected Connection newConnection( String connectionName, XAResource xaResource ) throws RepositorySourceException {
+        Connection c = new Connection(connectionName, this.loadDelay.get(), this.pingDelay.get());
+        c.setXaResource(xaResource);
+        return c;
+    }
+
+    protected void close( Connection conn ) {
+        if (conn != null && this.openConnections.remove(conn)) {
+            this.connectionsClosedCount.incrementAndGet();
+            this.loadCount.addAndGet(conn.getLoadCount());
+            this.pingCount.addAndGet(conn.getPingCount());
+        }
+    }
+
+    public int getOpenConnectionCount() {
+        return this.openConnections.size();
+    }
+
+    public int getTotalConnectionsCreated() {
+        return this.connectionsOpenedCount.get();
+    }
+
+    public int getTotalConnectionsClosed() {
+        return this.connectionsClosedCount.get();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Reference getReference() {
+        throw new UnsupportedOperationException();
+    }
+
+    public class Connection implements RepositoryConnection {
+
+        private final String connectionName;
+        private final AtomicBoolean closed = new AtomicBoolean(false);
+        private final AtomicBoolean loadResponse = new AtomicBoolean(true);
+        private final AtomicBoolean pingResponse = new AtomicBoolean(true);
+        private final AtomicLong closeCount = new AtomicLong(0);
+        private final AtomicLong loadCount = new AtomicLong(0);
+        private final AtomicLong loadDelay;
+        private final AtomicLong pingCount = new AtomicLong(0);
+        private final AtomicLong pingDelay;
+        private final AtomicReference<XAResource> xaResource = new AtomicReference<XAResource>();
+
+        protected Connection( String connectionName, long loadDelay, long pingDelay ) {
+            assert connectionName != null && connectionName.trim().length() != 0;
+            this.loadDelay = new AtomicLong(loadDelay);
+            this.pingDelay = new AtomicLong(pingDelay);
+            this.connectionName = connectionName;
+        }
+
+        public String getConnectionName() {
+            return this.connectionName;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void close() {
+            this.closeCount.incrementAndGet();
+            this.closed.set(true);
+            TimeDelayingRepositorySource.this.close(this);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public String getSourceName() {
+            return TimeDelayingRepositorySource.this.getName();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public CachePolicy getDefaultCachePolicy() {
+            return TimeDelayingRepositorySource.this.getDefaultCachePolicy();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public XAResource getXAResource() {
+            return this.xaResource.get();
+        }
+
+        public void setXaResource( XAResource xaResource ) {
+            this.xaResource.set(xaResource);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void execute( ExecutionEnvironment env, GraphCommand... commands ) throws RepositorySourceException, InterruptedException {
+            long delay = this.loadDelay.get();
+            if (delay > 0l) Thread.sleep(delay);
+            this.loadCount.incrementAndGet();
+        }
+
+        public void setLoadResponse( boolean response ) {
+            this.loadResponse.set(response);
+        }
+
+        public void setLoadDelay( long time, TimeUnit unit ) {
+            this.loadDelay.set(unit.toMillis(time));
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean ping( long time, TimeUnit unit ) throws InterruptedException {
+            Thread.sleep(this.pingDelay.get());
+            return this.pingResponse.get();
+        }
+
+        public void setPingResponse( boolean pingResponse ) {
+            this.pingResponse.set(pingResponse);
+        }
+
+        public void setPingDelay( long time, TimeUnit unit ) {
+            this.pingDelay.set(unit.toMillis(time));
+        }
+
+        public long getPingCount() {
+            return this.pingCount.get();
+        }
+
+        public long getLoadCount() {
+            return this.loadCount.get();
+        }
+
+        public long getCloseCount() {
+            return this.closeCount.get();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void setListener( RepositorySourceListener listener ) {
+        }
+
+    }
+
+}


Property changes on: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/TimeDelayingRepositorySource.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/BooleanValueFactoryTest.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/BooleanValueFactoryTest.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/BooleanValueFactoryTest.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -23,6 +23,7 @@
 
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
 import java.io.ByteArrayInputStream;
 import java.io.StringReader;
 import java.net.URI;
@@ -31,7 +32,6 @@
 import org.jboss.dna.spi.graph.Name;
 import org.jboss.dna.spi.graph.Path;
 import org.jboss.dna.spi.graph.Reference;
-import org.jmock.Mockery;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -43,7 +43,6 @@
 
     private BooleanValueFactory factory;
     private StringValueFactory stringFactory;
-    private Mockery context;
 
     /**
      * @throws java.lang.Exception
@@ -52,7 +51,6 @@
     public void setUp() throws Exception {
         stringFactory = new StringValueFactory(Path.URL_DECODER, Path.DEFAULT_ENCODER);
         factory = new BooleanValueFactory(Path.URL_DECODER, stringFactory);
-        context = new Mockery();
     }
 
     @Test
@@ -122,17 +120,17 @@
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateBooleanFromName() {
-        factory.create(context.mock(Name.class));
+        factory.create(mock(Name.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateBooleanFromPath() {
-        factory.create(context.mock(Path.class));
+        factory.create(mock(Path.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateBooleanFromReference() {
-        factory.create(context.mock(Reference.class));
+        factory.create(mock(Reference.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )

Modified: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/DecimalValueFactoryTest.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/DecimalValueFactoryTest.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/DecimalValueFactoryTest.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -23,6 +23,7 @@
 
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
 import java.io.ByteArrayInputStream;
 import java.io.StringReader;
 import java.math.BigDecimal;
@@ -32,7 +33,6 @@
 import org.jboss.dna.spi.graph.Name;
 import org.jboss.dna.spi.graph.Path;
 import org.jboss.dna.spi.graph.Reference;
-import org.jmock.Mockery;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -44,7 +44,6 @@
 
     private DecimalValueFactory factory;
     private StringValueFactory stringFactory;
-    private Mockery context;
 
     /**
      * @throws java.lang.Exception
@@ -53,7 +52,6 @@
     public void setUp() throws Exception {
         stringFactory = new StringValueFactory(Path.URL_DECODER, Path.DEFAULT_ENCODER);
         factory = new DecimalValueFactory(Path.URL_DECODER, stringFactory);
-        context = new Mockery();
     }
 
     @Test( expected = UnsupportedOperationException.class )
@@ -115,17 +113,17 @@
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateDecimalFromName() {
-        factory.create(context.mock(Name.class));
+        factory.create(mock(Name.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateDecimalFromPath() {
-        factory.create(context.mock(Path.class));
+        factory.create(mock(Path.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateDecimalFromReference() {
-        factory.create(context.mock(Reference.class));
+        factory.create(mock(Reference.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
@@ -160,8 +158,7 @@
     }
 
     @Test( expected = IllegalArgumentException.class )
-    public void shouldNotCreateDecimalFromInputStreamContainingUtf8EncodingOfStringWithContentsOtherThanDecimal()
-        throws Exception {
+    public void shouldNotCreateDecimalFromInputStreamContainingUtf8EncodingOfStringWithContentsOtherThanDecimal() throws Exception {
         factory.create(new ByteArrayInputStream("something".getBytes("UTF-8")));
     }
 

Modified: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/DoubleValueFactoryTest.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/DoubleValueFactoryTest.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/DoubleValueFactoryTest.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -23,6 +23,7 @@
 
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
 import java.io.ByteArrayInputStream;
 import java.io.StringReader;
 import java.math.BigDecimal;
@@ -32,7 +33,6 @@
 import org.jboss.dna.spi.graph.Name;
 import org.jboss.dna.spi.graph.Path;
 import org.jboss.dna.spi.graph.Reference;
-import org.jmock.Mockery;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -44,7 +44,6 @@
 
     private DoubleValueFactory factory;
     private StringValueFactory stringFactory;
-    private Mockery context;
 
     /**
      * @throws java.lang.Exception
@@ -53,7 +52,6 @@
     public void setUp() throws Exception {
         stringFactory = new StringValueFactory(Path.URL_DECODER, Path.URL_ENCODER);
         factory = new DoubleValueFactory(Path.URL_DECODER, stringFactory);
-        context = new Mockery();
     }
 
     @Test( expected = UnsupportedOperationException.class )
@@ -115,17 +113,17 @@
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateDoubleFromName() {
-        factory.create(context.mock(Name.class));
+        factory.create(mock(Name.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateDoubleFromPath() {
-        factory.create(context.mock(Path.class));
+        factory.create(mock(Path.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateDoubleFromReference() {
-        factory.create(context.mock(Reference.class));
+        factory.create(mock(Reference.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )

Modified: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/JodaDateTimeTest.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/JodaDateTimeTest.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/JodaDateTimeTest.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -22,8 +22,8 @@
 package org.jboss.dna.spi.graph.impl;
 
 import static org.hamcrest.core.Is.is;
-import static org.hamcrest.text.StringStartsWith.startsWith;
 import static org.junit.Assert.assertThat;
+import static org.jboss.dna.common.text.StringMatcher.startsWith;
 import org.junit.Before;
 import org.junit.Test;
 

Modified: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/JodaDateTimeValueFactoryTest.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/JodaDateTimeValueFactoryTest.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/JodaDateTimeValueFactoryTest.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -23,6 +23,7 @@
 
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
 import java.io.ByteArrayInputStream;
 import java.io.StringReader;
 import java.math.BigDecimal;
@@ -32,7 +33,6 @@
 import org.jboss.dna.spi.graph.Name;
 import org.jboss.dna.spi.graph.Path;
 import org.jboss.dna.spi.graph.Reference;
-import org.jmock.Mockery;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -53,7 +53,6 @@
 
     private JodaDateTimeValueFactory factory;
     private StringValueFactory stringFactory;
-    private Mockery context;
 
     /**
      * @throws java.lang.Exception
@@ -62,7 +61,6 @@
     public void setUp() throws Exception {
         stringFactory = new StringValueFactory(Path.URL_DECODER, Path.URL_ENCODER);
         factory = new JodaDateTimeValueFactory(Path.URL_DECODER, stringFactory);
-        context = new Mockery();
     }
 
     @Test( expected = UnsupportedOperationException.class )
@@ -127,17 +125,17 @@
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateDateFromName() {
-        factory.create(context.mock(Name.class));
+        factory.create(mock(Name.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateDateFromPath() {
-        factory.create(context.mock(Path.class));
+        factory.create(mock(Path.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateDateFromReference() {
-        factory.create(context.mock(Reference.class));
+        factory.create(mock(Reference.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
@@ -164,14 +162,12 @@
     }
 
     @Test( expected = IllegalArgumentException.class )
-    public void shouldNotCreateDateFromByteArrayContainingUtf8EncodingOfStringWithContentThatIsNotWellFormedDate()
-        throws Exception {
+    public void shouldNotCreateDateFromByteArrayContainingUtf8EncodingOfStringWithContentThatIsNotWellFormedDate() throws Exception {
         factory.create("something".getBytes("UTF-8"));
     }
 
     @Test( expected = IllegalArgumentException.class )
-    public void shouldNotCreateDateFromInputStreamContainingUtf8EncodingOfStringWithContentThatIsNotWellFormedDate()
-        throws Exception {
+    public void shouldNotCreateDateFromInputStreamContainingUtf8EncodingOfStringWithContentThatIsNotWellFormedDate() throws Exception {
         factory.create(new ByteArrayInputStream("something".getBytes("UTF-8")));
     }
 

Modified: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/LongValueFactoryTest.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/LongValueFactoryTest.java	2008-06-10 20:18:05 UTC (rev 252)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/impl/LongValueFactoryTest.java	2008-06-10 20:19:15 UTC (rev 253)
@@ -23,6 +23,7 @@
 
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
 import java.io.ByteArrayInputStream;
 import java.io.StringReader;
 import java.math.BigDecimal;
@@ -32,7 +33,6 @@
 import org.jboss.dna.spi.graph.Name;
 import org.jboss.dna.spi.graph.Path;
 import org.jboss.dna.spi.graph.Reference;
-import org.jmock.Mockery;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -44,7 +44,6 @@
 
     private LongValueFactory factory;
     private StringValueFactory stringFactory;
-    private Mockery context;
 
     /**
      * @throws java.lang.Exception
@@ -53,7 +52,6 @@
     public void setUp() throws Exception {
         stringFactory = new StringValueFactory(Path.URL_DECODER, Path.URL_ENCODER);
         factory = new LongValueFactory(Path.URL_DECODER, stringFactory);
-        context = new Mockery();
     }
 
     @Test( expected = UnsupportedOperationException.class )
@@ -117,17 +115,17 @@
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateLongFromName() {
-        factory.create(context.mock(Name.class));
+        factory.create(mock(Name.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateLongFromPath() {
-        factory.create(context.mock(Path.class));
+        factory.create(mock(Path.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )
     public void shouldNotCreateLongFromReference() {
-        factory.create(context.mock(Reference.class));
+        factory.create(mock(Reference.class));
     }
 
     @Test( expected = UnsupportedOperationException.class )




More information about the dna-commits mailing list