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

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Fri Jun 6 17:21:35 EDT 2008


Author: rhauch
Date: 2008-06-06 17:21:35 -0400 (Fri, 06 Jun 2008)
New Revision: 245

Added:
   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/FederatedRepositorySource.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/FederationException.java
   trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/
   trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java
   trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java
   trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.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/FederationService.java
   trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
Log:
Created initial implementations of RepositorySource, RepositoryConnection for the federation engine, along with test cases.  Also created a FederatedRepository class that represents the state associated a federated repository, the instances of which are managed by the FederationService.

Modified: trunk/dna-repository/pom.xml
===================================================================
--- trunk/dna-repository/pom.xml	2008-06-06 21:19:46 UTC (rev 244)
+++ trunk/dna-repository/pom.xml	2008-06-06 21:21:35 UTC (rev 245)
@@ -77,6 +77,11 @@
       <artifactId>jmock-junit4</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
     <!-- 
     Logging (require SLF4J API for compiling, but use Log4J and its SLF4J binding for testing) 
     -->

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-06 21:19:46 UTC (rev 244)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java	2008-06-06 21:21:35 UTC (rev 245)
@@ -108,6 +108,12 @@
 	public static I18n sequencingXmlDocument;
 	public static I18n canceledSequencingXmlDocument;
 
+    public static I18n interruptedWhileConnectingToFederationConfigurationRepository;
+    public static I18n interruptedWhileClosingConnectionToFederationConfigurationRepository;
+    public static I18n unableToCreateConnectionToFederatedRepository;
+    public static I18n unableToAuthenticateConnectionToFederatedRepository;
+    public static I18n repositoryHasBeenShutDown;
+
     static {
         try {
             I18n.initialize(RepositoryI18n.class);

Added: 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	                        (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java	2008-06-06 21:21:35 UTC (rev 245)
@@ -0,0 +1,343 @@
+/*
+ * 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 java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.repository.RepositoryI18n;
+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.RepositoryConnectionPool;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+
+/**
+ * The component in the {@link FederationService} that represents a single federated repository. The federated repository manages
+ * a set of {@link FederatedSource federated sources}, and provides the logic of interacting with those sources and presenting a
+ * single unified graph.
+ * 
+ * @author Randall Hauch
+ */
+ at ThreadSafe
+public class FederatedRepository {
+
+    /**
+     * The administrative component for this service.
+     * 
+     * @author Randall Hauch
+     */
+    protected class Administrator extends AbstractServiceAdministrator {
+
+        protected Administrator() {
+            super(RepositoryI18n.federationServiceName, State.STARTED);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        protected void doStart( State fromState ) {
+            super.doStart(fromState);
+            FederatedRepository.this.startRepository();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        protected void doShutdown( State fromState ) {
+            super.doShutdown(fromState);
+            FederatedRepository.this.shutdownRepository();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean awaitTermination( long timeout, TimeUnit unit ) throws InterruptedException {
+            return FederatedRepository.this.awaitTermination(timeout, unit);
+        }
+
+    }
+
+    private final ServiceAdministrator administrator = new Administrator();
+    private final String name;
+    private final FederationService service;
+    private final Lock sourcesWriteLock = new ReentrantLock();
+    private final List<FederatedSource> sources = new CopyOnWriteArrayList<FederatedSource>();
+    private final CopyOnWriteArrayList<RepositorySourceListener> listeners = new CopyOnWriteArrayList<RepositorySourceListener>();
+    private CachePolicy defaultCachePolicy;
+
+    /**
+     * Create a federated repository instance, as managed by the supplied {@link FederationService}.
+     * 
+     * @param service the federation service that is managing this instance
+     * @param name the name of the repository
+     * @throws IllegalArgumentException if the service is null or the name is null or blank
+     */
+    public FederatedRepository( FederationService service, String name ) {
+        ArgCheck.isNotNull(service, "service");
+        ArgCheck.isNotEmpty(name, "name");
+        this.name = name;
+        this.service = service;
+    }
+
+    /**
+     * Get the name of this repository
+     * 
+     * @return name
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * @return administrator
+     */
+    public ServiceAdministrator getAdministrator() {
+        return this.administrator;
+    }
+
+    /**
+     * Utility method called by the administrator.
+     */
+    protected void startRepository() {
+        // Do not establish connections to the sources; these will be established as needed
+    }
+
+    /**
+     * Utility method called by the administrator.
+     */
+    protected void shutdownRepository() {
+        // Close all connections to the sources. This is done inside the sources write lock.
+        try {
+            this.sourcesWriteLock.lock();
+            for (FederatedSource source : this.sources) {
+                source.getConnectionPool().shutdown();
+            }
+        } finally {
+            this.sourcesWriteLock.unlock();
+        }
+        // Connections to this repository check before doing anything with this, so just remove it from the service ...
+        this.service.removeRepository(this);
+    }
+
+    /**
+     * Utility method called by the administrator.
+     */
+    protected boolean awaitTermination( long timeout, TimeUnit unit ) throws InterruptedException {
+        // Check whether all source pools are shut down. This is done inside the sources write lock.
+        try {
+            this.sourcesWriteLock.lock();
+            for (FederatedSource source : this.sources) {
+                if (!source.getConnectionPool().awaitTermination(timeout, unit)) {
+                    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.
+     * </p>
+     * 
+     * @return the sources
+     */
+    public List<FederatedSource> getSources() {
+        return Collections.unmodifiableList(this.sources);
+    }
+
+    /**
+     * Add the supplied federated source. This method returns false if the source is null.
+     * <p>
+     * This method can safely be called while the federation repository is in use.
+     * </p>
+     * 
+     * @param source the source to add
+     * @return true if the source is added, or false if the reference is null or if there is already an existing source with the
+     * supplied name.
+     */
+    public boolean addSource( FederatedSource source ) {
+        if (source == null) return false;
+        try {
+            this.sourcesWriteLock.lock();
+            for (FederatedSource existingSource : this.sources) {
+                if (existingSource.getName().equals(source.getName())) return false;
+            }
+            this.sources.add(source);
+        } finally {
+            this.sourcesWriteLock.unlock();
+        }
+        return true;
+    }
+
+    /**
+     * Add the supplied federated source. This method returns false if the source is null.
+     * <p>
+     * This method can safely be called while the federation repository is in use.
+     * </p>
+     * 
+     * @param source the source to add
+     * @param index the index at which the source should be added
+     * @return true if the source is added, or false if the reference is null or if there is already an existing source with the
+     * supplied name.
+     * @throws IndexOutOfBoundsException if the index is out of bounds
+     */
+    public boolean addSource( FederatedSource source, int index ) {
+        if (source == null) return false;
+        try {
+            this.sourcesWriteLock.lock();
+            for (FederatedSource existingSource : this.sources) {
+                if (existingSource.getName().equals(source.getName())) return false;
+            }
+            this.sources.add(index, source);
+        } finally {
+            this.sourcesWriteLock.unlock();
+        }
+        return true;
+    }
+
+    /**
+     * Remove from this federated repository the supplied source (or a source with the same name as that supplied). This call
+     * shuts down the connections in the source in an orderly fashion, allowing those connection currently in use to be used and
+     * closed normally, but preventing further connections from being used.
+     * <p>
+     * This method can safely be called while the federation repository is in use.
+     * </p>
+     * 
+     * @param source the source to be removed
+     * @param timeToAwait the amount of time to wait while all of the source's connections are closed, or non-positive if the call
+     * should not wait at all
+     * @param unit the time unit to be used for <code>timeToAwait</code>
+     * @return true if the source was removed, or false if the source was not a source for this repository.
+     * @throws InterruptedException if the thread is interrupted while awaiting closing of the connections
+     */
+    public boolean removeSource( FederatedSource source, long timeToAwait, TimeUnit unit ) throws InterruptedException {
+        // Use the name; don't use the object equality ...
+        return removeSource(source.getName(), timeToAwait, unit) != null;
+    }
+
+    /**
+     * Remove from this federated repository the source with the supplied name. This call shuts down the connections in the source
+     * in an orderly fashion, allowing those connection currently in use to be used and closed normally, but preventing further
+     * connections from being used.
+     * <p>
+     * This method can safely be called while the federation repository is in use.
+     * </p>
+     * 
+     * @param name the name of the source to be removed
+     * @param timeToAwait the amount of time to wait while all of the source's connections are closed, or non-positive if the call
+     * should not wait at all
+     * @param unit the time unit to be used for <code>timeToAwait</code>
+     * @return the source with the supplied name that was removed, or null if no existing source matching the supplied name could
+     * be found
+     * @throws InterruptedException if the thread is interrupted while awaiting closing of the connections
+     */
+    public FederatedSource removeSource( String name, long timeToAwait, TimeUnit unit ) throws InterruptedException {
+        try {
+            this.sourcesWriteLock.lock();
+            for (FederatedSource existingSource : this.sources) {
+                if (existingSource.getName().equals(name)) {
+                    boolean removed = this.sources.remove(existingSource);
+                    assert removed;
+                    // Shut down the connection pool for the source ...
+                    RepositoryConnectionPool pool = existingSource.getConnectionPool();
+                    pool.shutdown();
+                    if (timeToAwait > 0l) pool.awaitTermination(timeToAwait, unit);
+                    return existingSource;
+                }
+            }
+        } finally {
+            this.sourcesWriteLock.unlock();
+        }
+        return null;
+    }
+
+    /**
+     * Add a listener that is to receive notifications to changes to content within this repository. This method does nothing if
+     * the supplied listener is null.
+     * 
+     * @param listener the new listener
+     */
+    public void addListener( RepositorySourceListener listener ) {
+        if (listener == null) return;
+        this.listeners.addIfAbsent(listener);
+    }
+
+    /**
+     * Remove the supplied listener. This method does nothing if the supplied listener is null.
+     * <p>
+     * This method can safely be called while the federation repository is in use.
+     * </p>
+     * 
+     * @param listener the listener to remove
+     * @return true if the listener was removed, or false if the listener was not registered
+     */
+    public boolean removeListener( RepositorySourceListener listener ) {
+        if (listener == null) return false;
+        return this.listeners.remove(listener);
+    }
+
+    /**
+     * Authenticate the supplied username with the supplied credentials, and return whether authentication was successful.
+     * 
+     * @param username the username
+     * @param credentials the credentials
+     * @return true if authentication succeeded, or false otherwise
+     */
+    public boolean authenticate( String username, Object credentials ) {
+        return true;
+    }
+
+    /**
+     * Get the default cache policy for the repository with the supplied name
+     * 
+     * @return the default cache policy
+     */
+    public CachePolicy getDefaultCachePolicy() {
+        return defaultCachePolicy;
+    }
+
+    /**
+     * Set the default cache policy for the federated repository.
+     * <p>
+     * This method can safely be called while the federation repository is in use.
+     * </p>
+     * 
+     * @param defaultCachePolicy Sets defaultCachePolicy to the specified value.
+     */
+    public void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
+        ArgCheck.isNotNull(defaultCachePolicy, "defaultCachePolicy");
+        this.defaultCachePolicy = defaultCachePolicy;
+    }
+
+}


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

Added: 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	                        (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java	2008-06-06 21:21:35 UTC (rev 245)
@@ -0,0 +1,129 @@
+/*
+ * 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 java.util.concurrent.TimeUnit;
+import javax.transaction.xa.XAResource;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+
+/**
+ * @author Randall Hauch
+ */
+ at ThreadSafe
+public class FederatedRepositoryConnection implements RepositoryConnection {
+
+    protected static final RepositorySourceListener NO_OP_LISTENER = new RepositorySourceListener() {
+
+        public void notify( String sourceName, Object... events ) {
+            // do nothing
+        }
+    };
+
+    private final FederatedRepository repository;
+    private final FederatedRepositorySource source;
+    private RepositorySourceListener listener = NO_OP_LISTENER;
+
+    protected FederatedRepositoryConnection( FederatedRepository repository, FederatedRepositorySource source ) {
+        assert source != null;
+        assert repository != null;
+        this.source = source;
+        this.repository = repository;
+    }
+
+    /**
+     * @return repository
+     */
+    protected FederatedRepository getRepository() {
+        return this.repository;
+    }
+
+    /**
+     * @return source
+     */
+    protected FederatedRepositorySource getRepositorySource() {
+        return this.source;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSourceName() {
+        return this.source.getName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public CachePolicy getDefaultCachePolicy() {
+        return this.repository.getDefaultCachePolicy();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public XAResource getXAResource() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setListener( RepositorySourceListener listener ) {
+        RepositorySourceListener oldListener = this.listener;
+        this.listener = listener != null ? listener : NO_OP_LISTENER;
+        this.repository.addListener(this.listener);
+        if (oldListener != NO_OP_LISTENER) {
+            this.repository.removeListener(oldListener);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean ping( long time, TimeUnit unit ) {
+        return this.repository.getAdministrator().isStarted();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void execute( ExecutionEnvironment env, GraphCommand... commands ) throws RepositorySourceException {
+        if (!this.repository.getAdministrator().isStarted()) {
+            throw new RepositorySourceException(RepositoryI18n.repositoryHasBeenShutDown.text(this.repository.getName()));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() {
+        this.repository.removeListener(this.listener);
+    }
+
+}


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

Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositorySource.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositorySource.java	                        (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositorySource.java	2008-06-06 21:21:35 UTC (rev 245)
@@ -0,0 +1,246 @@
+/*
+ * 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 java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import javax.naming.Context;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.ObjectFactory;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+
+/**
+ * @author Randall Hauch
+ */
+ at ThreadSafe
+public class FederatedRepositorySource implements RepositorySource {
+
+    public static final int DEFAULT_RETRY_LIMIT = 0;
+
+    protected static final String USERNAME = "username";
+    protected static final String CREDENTIALS = "credentials";
+    protected static final String SOURCE_NAME = "sourceName";
+    protected static final String REPOSITORY_NAME = "repositoryName";
+    protected static final String RETRY_LIMIT = "retryLimit";
+    protected static final String FEDERATION_SERVICE_JNDI_NAME = "fedServiceJndiName";
+
+    private final String repositoryName;
+    private final FederationService federationService;
+    private String sourceName;
+    private int retryLimit;
+    private String username;
+    private String credentials;
+
+    /**
+     * 
+     */
+    protected FederatedRepositorySource( FederationService federationService, String repositoryName ) {
+        ArgCheck.isNotNull(federationService, "federationService");
+        ArgCheck.isNotNull(repositoryName, "repositoryName");
+        this.federationService = federationService;
+        this.repositoryName = repositoryName;
+        this.retryLimit = DEFAULT_RETRY_LIMIT;
+    }
+
+    /**
+     * @return federationService
+     */
+    public FederationService getFederationService() {
+        return this.federationService;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getRetryLimit() {
+        return this.retryLimit;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRetryLimit( int limit ) {
+        this.retryLimit = limit > 0 ? limit : 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public RepositoryConnection getConnection() throws RepositorySourceException {
+        // Find the repository ...
+        FederatedRepository repository = federationService.getRepository(this.repositoryName);
+        if (repository == null) {
+            throw new RepositorySourceException(RepositoryI18n.unableToCreateConnectionToFederatedRepository.text(this.repositoryName));
+        }
+        // Authenticate the user ...
+        String username = this.username;
+        Object credentials = this.credentials;
+        if (!repository.authenticate(username, credentials)) {
+            throw new RepositorySourceException(RepositoryI18n.unableToAuthenticateConnectionToFederatedRepository.text(this.repositoryName, username));
+        }
+        // Return the new connection ...
+        return new FederatedRepositoryConnection(repository, this);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName() {
+        return sourceName;
+    }
+
+    /**
+     * @param sourceName the name of this repository source
+     */
+    public void setName( String sourceName ) {
+        this.sourceName = sourceName;
+    }
+
+    /**
+     * @return username
+     */
+    public String getUsername() {
+        return this.username;
+    }
+
+    /**
+     * @param username Sets username to the specified value.
+     */
+    public void setUsername( String username ) {
+        this.username = username;
+    }
+
+    /**
+     * @return credentials
+     */
+    public String getCredentials() {
+        return this.credentials;
+    }
+
+    /**
+     * @param credentials Sets credentials to the specified value.
+     */
+    public void setCredentials( String credentials ) {
+        this.credentials = credentials;
+    }
+
+    /**
+     * @return repositoryName
+     */
+    public String getRepositoryName() {
+        return this.repositoryName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Reference getReference() {
+        String className = getClass().getName();
+        String factoryClassName = NamingContextObjectFactory.class.getName();
+        Reference ref = new Reference(className, factoryClassName, null);
+
+        ref.add(new StringRefAddr(USERNAME, this.getUsername()));
+        ref.add(new StringRefAddr(CREDENTIALS, this.getCredentials()));
+        ref.add(new StringRefAddr(SOURCE_NAME, this.sourceName));
+        ref.add(new StringRefAddr(REPOSITORY_NAME, this.repositoryName));
+        ref.add(new StringRefAddr(FEDERATION_SERVICE_JNDI_NAME, this.federationService.getJndiName()));
+        ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
+        return ref;
+    }
+
+    public static class NamingContextObjectFactory implements ObjectFactory {
+
+        public NamingContextObjectFactory() {
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Object getObjectInstance( Object obj, javax.naming.Name name, Context nameCtx, Hashtable<?, ?> environment ) throws Exception {
+            if (obj instanceof Reference) {
+                Map<String, String> values = new HashMap<String, String>();
+                Reference ref = (Reference)obj;
+                Enumeration<?> en = ref.getAll();
+                while (en.hasMoreElements()) {
+                    RefAddr subref = (RefAddr)en.nextElement();
+                    String key = subref.getType();
+                    Object value = subref.getContent();
+                    values.put(key, (String)value);
+                }
+                String repositoryName = values.get(FederatedRepositorySource.REPOSITORY_NAME);
+                String username = values.get(FederatedRepositorySource.USERNAME);
+                String credentials = values.get(FederatedRepositorySource.CREDENTIALS);
+                String retryLimit = values.get(FederatedRepositorySource.RETRY_LIMIT);
+                String sourceName = values.get(FederatedRepositorySource.SOURCE_NAME);
+                String federationSourceJndiName = values.get(FederatedRepositorySource.FEDERATION_SERVICE_JNDI_NAME);
+
+                // Look for the federation service ...
+                FederationService federationService = (FederationService)nameCtx.lookup(federationSourceJndiName);
+                FederatedRepositorySource source = new FederatedRepositorySource(federationService, repositoryName);
+                if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit));
+                if (sourceName != null) source.setName(sourceName);
+                if (username != null) source.setUsername(username);
+                if (credentials != null) source.setCredentials(credentials);
+                return source;
+            }
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return repositoryName.hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj ) {
+        if (obj == this) return true;
+        if (obj instanceof FederatedRepositorySource) {
+            FederatedRepositorySource that = (FederatedRepositorySource)obj;
+            // The repository name, source name, and federation service must all match
+            if (!this.getRepositoryName().equals(that.getRepositoryName())) return false;
+            if (!this.getFederationService().equals(that.getFederationService())) return false;
+            if (this.getName() == null) {
+                if (that.getName() != null) return false;
+            } else {
+                if (!this.getName().equals(that.getName())) return false;
+            }
+            return true;
+        }
+        return false;
+    }
+}


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

Added: 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	                        (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java	2008-06-06 21:21:35 UTC (rev 245)
@@ -0,0 +1,131 @@
+/*
+ * 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 java.util.concurrent.TimeUnit;
+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.RepositoryConnectionPool;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+
+/**
+ * A component that represents a {@link RepositorySource repository source} (with its state) being federated in a
+ * {@link FederatedRepository}.
+ * 
+ * @author Randall Hauch
+ */
+ at ThreadSafe
+public class FederatedSource {
+
+    private final RepositorySource source;
+    private final RepositoryConnectionPool connectionPool;
+
+    public FederatedSource( RepositorySource source ) {
+        ArgCheck.isNotNull(source, "source");
+        this.source = source;
+        this.connectionPool = new RepositoryConnectionPool(source);
+    }
+
+    /**
+     * Get the name for this federated repository source.
+     * 
+     * @return the name; never null or empty
+     */
+    public String getName() {
+        return this.source.getName();
+    }
+
+    /**
+     * Get the RepositorySource repository source information for this federated source.
+     * 
+     * @return the repository source; never null
+     */
+    public RepositorySource getRepositorySource() {
+        return this.source;
+    }
+
+    /**
+     * Get the connection pool used by this federated source.
+     * 
+     * @return the connection pool; never null
+     */
+    protected RepositoryConnectionPool getConnectionPool() {
+        return this.connectionPool;
+    }
+
+    /**
+     * Determine whether the federated source is available by attempting to connect to the source and
+     * {@link RepositoryConnection#ping(long, TimeUnit) pinging} the source.
+     * 
+     * @param timeToWait the time the caller is willing to wait to establish a connection
+     * @param unit the time unit for the <code>timeToWait</code> parameter; may not be null
+     * @return true if the federated source is available, or false if the source is not available in the allotted time period
+     */
+    public boolean isAvailable( long timeToWait, TimeUnit unit ) {
+        RepositoryConnection connection = null;
+        try {
+            connection = this.connectionPool.getConnection();
+            return connection.ping(timeToWait, unit);
+        } catch (IllegalStateException e) {
+            // The connection pool is not running, so return false ..
+            return false;
+        } catch (InterruptedException e) {
+            // Consider an attempt to get a connection and being interrupted as NOT being connected
+            return false;
+        } catch (Throwable e) {
+            // Consider any other failure, including RepositorySourceException, as meaning not available
+            return false;
+        } finally {
+            if (connection != null) {
+                try {
+                    connection.close();
+                } catch (InterruptedException e) {
+                    // Consider an attempt to get a connection and being interrupted as NOT being connected
+                    return false;
+                }
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return source.getName().hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj ) {
+        if (obj instanceof FederatedSource) {
+            FederatedSource that = (FederatedSource)obj;
+            if (!this.source.getName().equals(that.source.getName())) return false;
+            return true;
+        }
+        return false;
+    }
+
+}


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

Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationException.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationException.java	                        (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationException.java	2008-06-06 21:21:35 UTC (rev 245)
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+
+/**
+ * 
+ * @author Randall Hauch
+ */
+public class FederationException extends RuntimeException {
+
+    /**
+     * 
+     */
+    public FederationException() {
+    }
+
+    /**
+     * @param message
+     */
+    public FederationException( String message ) {
+        super(message);
+
+    }
+
+    /**
+     * @param cause
+     */
+    public FederationException( Throwable cause ) {
+        super(cause);
+
+    }
+
+    /**
+     * @param message
+     * @param cause
+     */
+    public FederationException( String message, Throwable cause ) {
+        super(message, cause);
+
+    }
+
+}


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

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-06 21:19:46 UTC (rev 244)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java	2008-06-06 21:21:35 UTC (rev 245)
@@ -21,21 +21,29 @@
  */
 package org.jboss.dna.repository.federation;
 
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
+import net.jcip.annotations.ThreadSafe;
 import org.jboss.dna.common.util.ArgCheck;
 import org.jboss.dna.repository.RepositoryI18n;
 import org.jboss.dna.repository.services.AbstractServiceAdministrator;
 import org.jboss.dna.repository.services.AdministeredService;
 import org.jboss.dna.repository.services.ServiceAdministrator;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
 import org.jboss.dna.spi.graph.connection.RepositorySource;
 
 /**
  * @author Randall Hauch
  */
+ at ThreadSafe
 public class FederationService implements AdministeredService {
 
     /**
      * The administrative component for this service.
+     * 
      * @author Randall Hauch
      */
     protected class Administrator extends AbstractServiceAdministrator {
@@ -47,22 +55,44 @@
         /**
          * {@inheritDoc}
          */
+        @Override
+        protected void doStart( State fromState ) {
+            super.doStart(fromState);
+            startService();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        protected void doShutdown( State fromState ) {
+            super.doShutdown(fromState);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
         public boolean awaitTermination( long timeout, TimeUnit unit ) {
             return true;
         }
 
     }
 
-    private RepositorySource bootstrapSource;
+    private final RepositorySource configurationSource;
     private final Administrator administrator = new Administrator();
+    private final ConcurrentMap<String, FederatedRepository> repositories = new ConcurrentHashMap<String, FederatedRepository>();
+    private RepositoryConnection configurationConnection;
 
     /**
      * Create a federation service instance
-     * @param bootstrapSource the repository source that should be used to bootstrap the federation service
+     * 
+     * @param configurationSource the repository source that contains the configuration for this federation service (including the
+     * respositories and the sources used by the federated repositories)
      * @throws IllegalArgumentException if the bootstrap source is null
      */
-    public FederationService( RepositorySource bootstrapSource ) {
-        ArgCheck.isNotNull(bootstrapSource, "bootstrapSource");
+    public FederationService( RepositorySource configurationSource ) {
+        ArgCheck.isNotNull(configurationSource, "configurationSource");
+        this.configurationSource = configurationSource;
     }
 
     /**
@@ -73,12 +103,98 @@
     }
 
     /**
-     * Get the repository source used to obtain connections to the repository containing the configuration information for this
-     * federation service.
-     * @return bootstrapSource
+     * Get the source for the repository containing the configuration for this federation service.
+     * 
+     * @return the configuration repository source; never null
      */
-    public RepositorySource getBootstrapSource() {
-        return this.bootstrapSource;
+    public RepositorySource getConfigurationSource() {
+        return this.configurationSource;
     }
 
+    public String getJndiName() {
+        // TODO
+        return null;
+    }
+
+    protected void startService() {
+        if (this.configurationConnection == null) {
+            try {
+                this.configurationConnection = this.configurationSource.getConnection();
+            } catch (InterruptedException err) {
+                throw new FederationException(RepositoryI18n.interruptedWhileConnectingToFederationConfigurationRepository.text(this.configurationSource.getName()));
+            }
+        }
+    }
+
+    /**
+     * Get the federated repository object with the given name. The resulting repository will be started and ready to use.
+     * 
+     * @param name the name of the repository
+     * @return the repository instance
+     */
+    protected FederatedRepository getRepository( String name ) {
+        // Look for an existing repository ...
+        FederatedRepository repository = this.repositories.get(name);
+        if (repository == null) {
+            // Look up the node representing the repository in the configuration ...
+
+            // New up a repository and configure it ...
+            repository = new FederatedRepository(this, name);
+            // Now register it, being careful to not overwrite any added since previous call ..
+            FederatedRepository existingRepository = this.repositories.putIfAbsent(name, repository);
+            if (existingRepository != null) repository = existingRepository;
+        }
+        // Make sure it's started. By doing this here, whoever finds it in the map will start it.
+        repository.getAdministrator().start();
+        return repository;
+    }
+
+    protected void shutdownService() {
+        if (this.configurationConnection != null) {
+            try {
+                this.configurationConnection.close();
+            } catch (InterruptedException err) {
+                throw new FederationException(RepositoryI18n.interruptedWhileClosingConnectionToFederationConfigurationRepository.text(this.configurationSource.getName()));
+            }
+            // Now shut down all repositories ...
+            for (String repositoryName : this.repositories.keySet()) {
+                FederatedRepository repository = this.repositories.get(repositoryName);
+                repository.getAdministrator().shutdown();
+            }
+        }
+    }
+
+    /**
+     * Create a {@link RepositorySource} that can be used to establish connections to the federated repository with the supplied
+     * name.
+     * 
+     * @param repositoryName the name of the federated repository
+     * @return the source that can be configured and used to establish connection to the repository
+     */
+    public RepositorySource createRepositorySource( String repositoryName ) {
+        FederatedRepositorySource source = new FederatedRepositorySource(this, repositoryName);
+        return source;
+    }
+
+    /**
+     * Get the current set of repository names.
+     * 
+     * @return the unmodifiable names of the repository.
+     */
+    public Set<String> getRepositoryNames() {
+        return Collections.unmodifiableSet(this.repositories.keySet());
+    }
+
+    protected void removeRepository( FederatedRepository repository ) {
+        this.repositories.remove(repository.getName(), repository);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals( Object obj ) {
+        if (obj == this) return true;
+        return false;
+    }
 }

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-06 21:19:46 UTC (rev 244)
+++ trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties	2008-06-06 21:21:35 UTC (rev 245)
@@ -93,4 +93,10 @@
 
 errorSequencingXmlDocument = An error occurred while sequencing XML:
 sequencingXmlDocument = Sequencing XML
-canceledSequencingXmlDocument = Canceled sequencing XML
\ No newline at end of file
+canceledSequencingXmlDocument = Canceled sequencing XML
+
+interruptedWhileConnectingToFederationConfigurationRepository = Interrupted while connecting to federation configuration repository for "{0}" repository
+interruptedWhileClosingConnectionToFederationConfigurationRepository = Interrupted while closing connection to federation configuration repository for "{0}" repository 
+unableToCreateConnectionToFederatedRepository = Unable to create a connection to the repository "{0}". Check the Federation Service configuration.
+unableToAuthenticateConnectionToFederatedRepository = Unable to authenticate "{1}" for repository "{0}"
+repositoryHasBeenShutDown = The "{0}" repository has been shut down and may no longer be used.

Added: 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	                        (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryConnectionTest.java	2008-06-06 21:21:35 UTC (rev 245)
@@ -0,0 +1,133 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors. 
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.repository.federation;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.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.repository.services.ServiceAdministrator;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederatedRepositoryConnectionTest {
+
+    private FederatedRepositoryConnection connection;
+    private FederatedRepositorySource source;
+    private FederatedRepository repository;
+    private String sourceName;
+    private CachePolicy defaultCachePolicy;
+    private ServiceAdministrator repositoryAdmin;
+
+    @Before
+    public void beforeEach() throws Exception {
+        sourceName = "Source X";
+        source = mock(FederatedRepositorySource.class);
+        stub(source.getName()).toReturn(sourceName);
+        repository = mock(FederatedRepository.class);
+        defaultCachePolicy = mock(CachePolicy.class);
+        stub(repository.getDefaultCachePolicy()).toReturn(defaultCachePolicy);
+        repositoryAdmin = mock(ServiceAdministrator.class);
+        stub(repository.getAdministrator()).toReturn(repositoryAdmin);
+        connection = new FederatedRepositoryConnection(repository, source);
+    }
+
+    @Test
+    public void shouldHaveSourceAndRepository() {
+        assertThat(connection.getRepository(), is(repository));
+        assertThat(connection.getRepositorySource(), is(source));
+    }
+
+    @Test
+    public void shouldGetSourceNameFromSource() {
+        for (int i = 0; i != 10; ++i) {
+            assertThat(connection.getSourceName(), is(sourceName));
+        }
+        verify(source, times(10)).getName();
+    }
+
+    @Test
+    public void shouldGetDefaultCachePolicyFromRepository() {
+        assertThat(connection.getDefaultCachePolicy(), is(sameInstance(defaultCachePolicy)));
+        verify(repository, times(1)).getDefaultCachePolicy();
+    }
+
+    @Test
+    public void shouldHaveNoXaResource() {
+        assertThat(connection.getXAResource(), is(nullValue()));
+    }
+
+    @Test
+    public void shouldCheckRepositoryAdminsStartedStateForPingResult() {
+        stub(repositoryAdmin.isStarted()).toReturn(true);
+        assertThat(connection.ping(1, TimeUnit.SECONDS), is(true));
+        verify(repositoryAdmin, times(1)).isStarted();
+    }
+
+    @Test( expected = RepositorySourceException.class )
+    public void shouldFailExecutionIfRepositoryAdminsIsNotStarted() {
+        stub(repositoryAdmin.isStarted()).toReturn(false);
+        ExecutionEnvironment env = mock(ExecutionEnvironment.class);
+        GraphCommand command = mock(GraphCommand.class);
+        connection.execute(env, command);
+    }
+
+    @Test
+    public void shouldAddListenerToRepositoryWhenSetOnConnection() {
+        // Old listener is no-op, so it is not removed from repository ...
+        RepositorySourceListener listener = mock(RepositorySourceListener.class);
+        connection.setListener(listener);
+        verify(repository, times(1)).addListener(listener);
+
+        // Old listener is NOT no-op, so it is removed from repository ...
+        RepositorySourceListener listener2 = mock(RepositorySourceListener.class);
+        connection.setListener(listener2);
+        verify(repository, times(1)).removeListener(listener);
+        verify(repository, times(1)).addListener(listener2);
+    }
+
+    @Test
+    public void shouldRemoveListenerFromRepositoryWhenConnectionIsClosed() {
+        // Old listener is NOT no-op, so it is removed from repository ...
+        RepositorySourceListener listener2 = mock(RepositorySourceListener.class);
+        connection.setListener(listener2);
+        verify(repository, times(1)).addListener(listener2);
+
+        // Closing connection will remove listener ...
+        connection.close();
+        verify(repository, times(1)).removeListener(listener2);
+    }
+
+}


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

Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java	                        (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositorySourceTest.java	2008-06-06 21:21:35 UTC (rev 245)
@@ -0,0 +1,218 @@
+/*
+ * 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.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+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.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederatedRepositorySourceTest {
+
+    private FederatedRepositorySource source;
+    private FederatedRepositoryConnection connection;
+    private FederatedRepository repository;
+    private FederationService service;
+    private String repositoryName;
+    private String username;
+    private String credentials;
+
+    /**
+     * @throws java.lang.Exception
+     */
+    @Before
+    public void beforeEach() throws Exception {
+        this.repositoryName = "Test Repository";
+        this.service = mock(FederationService.class);
+        this.source = new FederatedRepositorySource(service, repositoryName);
+        this.repository = mock(FederatedRepository.class);
+        this.username = "valid username";
+        this.credentials = "valid password";
+        this.source.setUsername(username);
+        this.source.setCredentials(credentials);
+    }
+
+    @Test
+    public void shouldCreateConnectionsByAuthenticateUsingFederationRepository() throws Exception {
+        stub(repository.authenticate(source.getUsername(), source.getCredentials())).toReturn(true);
+        stub(service.getRepository(source.getRepositoryName())).toReturn(repository);
+        connection = (FederatedRepositoryConnection)source.getConnection();
+        assertThat(connection, is(notNullValue()));
+        assertThat(connection.getRepository(), is(sameInstance(repository)));
+        verify(repository, times(1)).authenticate(source.getUsername(), source.getCredentials());
+        verify(service, times(1)).getRepository(source.getRepositoryName());
+    }
+
+    @Test( expected = RepositorySourceException.class )
+    public void shouldNotCreateConnectionWhenAuthenticationFails() throws Exception {
+        stub(repository.authenticate(source.getUsername(), source.getCredentials())).toReturn(false);
+        stub(service.getRepository(source.getRepositoryName())).toReturn(repository);
+        connection = (FederatedRepositoryConnection)source.getConnection();
+    }
+
+    @Test
+    public void shouldHaveNameSuppliedInConstructor() {
+        assertThat(source.getRepositoryName(), is(repositoryName));
+    }
+
+    @Test
+    public void shouldHaveNullSourceNameUponConstruction() {
+        assertThat(source.getName(), is(nullValue()));
+    }
+
+    @Test
+    public void shouldAllowSettingName() {
+        source.setName("Something");
+        assertThat(source.getName(), is("Something"));
+        source.setName("another name");
+        assertThat(source.getName(), is("another name"));
+    }
+
+    @Test
+    public void shouldAllowSettingNameToNull() {
+        source.setName("some name");
+        source.setName(null);
+        assertThat(source.getName(), is(nullValue()));
+    }
+
+    @Test
+    public void shouldAllowSettingUsername() {
+        source.setUsername("Something");
+        assertThat(source.getUsername(), is("Something"));
+        source.setUsername("another name");
+        assertThat(source.getUsername(), is("another name"));
+    }
+
+    @Test
+    public void shouldAllowSettingUsernameToNull() {
+        source.setUsername("some name");
+        source.setUsername(null);
+        assertThat(source.getUsername(), is(nullValue()));
+    }
+
+    @Test
+    public void shouldAllowSettingCredentials() {
+        source.setCredentials("Something");
+        assertThat(source.getCredentials(), is("Something"));
+        source.setCredentials("another name");
+        assertThat(source.getCredentials(), is("another name"));
+    }
+
+    @Test
+    public void shouldAllowSettingCredentialsToNull() {
+        source.setCredentials("some name");
+        source.setCredentials(null);
+        assertThat(source.getCredentials(), is(nullValue()));
+    }
+
+    @Test
+    public void shouldHaveDefaultRetryLimit() {
+        assertThat(source.getRetryLimit(), is(FederatedRepositorySource.DEFAULT_RETRY_LIMIT));
+    }
+
+    @Test
+    public void shouldSetRetryLimitToZeroWhenSetWithNonPositiveValue() {
+        source.setRetryLimit(0);
+        assertThat(source.getRetryLimit(), is(0));
+        source.setRetryLimit(-1);
+        assertThat(source.getRetryLimit(), is(0));
+        source.setRetryLimit(-100);
+        assertThat(source.getRetryLimit(), is(0));
+    }
+
+    @Test
+    public void shouldAllowRetryLimitToBeSet() {
+        for (int i = 0; i != 100; ++i) {
+            source.setRetryLimit(i);
+            assertThat(source.getRetryLimit(), is(i));
+        }
+    }
+
+    @Test
+    public void shouldCreateJndiReferenceAndRecreatedObjectFromReference() throws Exception {
+        String serviceJndiName = "jndiName";
+        stub(service.getJndiName()).toReturn(serviceJndiName);
+
+        int retryLimit = 100;
+        source.setCredentials(credentials);
+        source.setUsername(username);
+        source.setRetryLimit(retryLimit);
+        source.setName("Some source");
+
+        Reference ref = source.getReference();
+        assertThat(ref.getClassName(), is(FederatedRepositorySource.class.getName()));
+        assertThat(ref.getFactoryClassName(), is(FederatedRepositorySource.NamingContextObjectFactory.class.getName()));
+
+        Map<String, Object> refAttributes = new HashMap<String, Object>();
+        Enumeration<RefAddr> enumeration = ref.getAll();
+        while (enumeration.hasMoreElements()) {
+            RefAddr addr = enumeration.nextElement();
+            refAttributes.put(addr.getType(), addr.getContent());
+        }
+
+        assertThat(refAttributes.remove(FederatedRepositorySource.USERNAME), is((Object)username));
+        assertThat(refAttributes.remove(FederatedRepositorySource.CREDENTIALS), is((Object)credentials));
+        assertThat(refAttributes.remove(FederatedRepositorySource.SOURCE_NAME), is((Object)source.getName()));
+        assertThat(refAttributes.remove(FederatedRepositorySource.REPOSITORY_NAME), is((Object)repositoryName));
+        assertThat(refAttributes.remove(FederatedRepositorySource.FEDERATION_SERVICE_JNDI_NAME), is((Object)serviceJndiName));
+        assertThat(refAttributes.remove(FederatedRepositorySource.RETRY_LIMIT), is((Object)Integer.toString(retryLimit)));
+        assertThat(refAttributes.isEmpty(), is(true));
+
+        // Recreate the object, use a newly constructed source ...
+        FederatedRepositorySource.NamingContextObjectFactory factory = new FederatedRepositorySource.NamingContextObjectFactory();
+        Name name = mock(Name.class);
+        Context context = mock(Context.class);
+        stub(context.lookup(serviceJndiName)).toReturn(service);
+        Hashtable<?, ?> env = new Hashtable<Object, Object>();
+        FederatedRepositorySource recoveredSource = (FederatedRepositorySource)factory.getObjectInstance(ref, name, context, env);
+        assertThat(recoveredSource, is(notNullValue()));
+
+        assertThat(recoveredSource.getName(), is(source.getName()));
+        assertThat(recoveredSource.getUsername(), is(source.getUsername()));
+        assertThat(recoveredSource.getCredentials(), is(source.getCredentials()));
+        assertThat(recoveredSource.getRepositoryName(), is(source.getRepositoryName()));
+        assertThat(recoveredSource.getRetryLimit(), is(source.getRetryLimit()));
+        assertThat(recoveredSource.getFederationService(), is(service));
+
+        assertThat(recoveredSource.equals(source), is(true));
+        assertThat(source.equals(recoveredSource), is(true));
+    }
+}


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

Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java	                        (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java	2008-06-06 21:21:35 UTC (rev 245)
@@ -0,0 +1,174 @@
+/*
+ * 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 java.util.concurrent.TimeUnit;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.junit.Assert.assertThat;
+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 org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionPool;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+import org.jboss.dna.spi.graph.connection.RepositorySourceException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederatedSourceTest {
+
+    private RepositoryConnection connection;
+    private FederatedSource source;
+    private RepositorySource repositorySource;
+
+    /**
+     * @throws java.lang.Exception
+     */
+    @Before
+    public void beforeEach() throws Exception {
+        this.repositorySource = mock(RepositorySource.class);
+        this.source = new FederatedSource(this.repositorySource);
+        this.connection = mock(RepositoryConnection.class);
+    }
+
+    @After
+    public void afterEach() throws Exception {
+        RepositoryConnectionPool pool = source.getConnectionPool();
+        pool.shutdown();
+        pool.awaitTermination(1, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void shouldConstructWithNonNullRepositorySource() {
+        assertThat(source, is(notNullValue()));
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldFailToConstructWithNullRepositorySource() {
+        new FederatedSource(null);
+    }
+
+    @Test
+    public void shouldHaveConnectionPoolAfterConstruction() {
+        assertThat(source.getConnectionPool(), is(notNullValue()));
+    }
+
+    @Test
+    public void shouldGetTheNameFromTheRepositorySource() {
+        String theName = "My Repository";
+        stub(repositorySource.getName()).toReturn(theName);
+        assertThat(source.getName(), is(theName));
+        verify(repositorySource, times(1)).getName();
+
+        // Change the name of the source, and try again ...
+        theName = theName + " part deux";
+        stub(repositorySource.getName()).toReturn(theName);
+        assertThat(source.getName(), is(theName));
+        verify(repositorySource, times(2)).getName();
+    }
+
+    @Test
+    public void shouldCheckAvailabilityByCreatingConnectionAndPing() throws Exception {
+        // Set up the connection mock to return value from ping, and then
+        // set up the source mock to return the connection ...
+        stub(this.repositorySource.getConnection()).toReturn(connection);
+        stub(connection.ping(1, TimeUnit.SECONDS)).toReturn(true);
+        assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(true));
+    }
+
+    @Test
+    public void shouldConsiderSourceToNotBeAvailabilityWhenUnableToPingConnection() throws Exception {
+        // Set up the connection mock to return value from ping, and then
+        // set up the source mock to return the connection ...
+        stub(this.repositorySource.getConnection()).toReturn(connection);
+        stub(connection.ping(1, TimeUnit.SECONDS)).toReturn(false);
+        assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+    }
+
+    @Test
+    public void shouldConsiderSourceToNotBeAvailabilityWhenPingThrowsException() throws Exception {
+        // Set up the connection mock to return value from ping, and then
+        // set up the source mock to return the connection ...
+        stub(this.repositorySource.getConnection()).toReturn(connection);
+        stub(connection.ping(1, TimeUnit.SECONDS)).toThrow(new NullPointerException("sorry"));
+        assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+    }
+
+    @Test
+    public void shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsRepositorySourceException() throws Exception {
+        // Set up the connection mock to return value from ping, and then
+        // set up the source mock to return the connection ...
+        stub(this.repositorySource.getConnection()).toThrow(new RepositorySourceException("sorry"));
+        assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+    }
+
+    @Test
+    public void shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsIllegalStateException() throws Exception {
+        stub(this.repositorySource.getConnection()).toThrow(new IllegalStateException("sorry"));
+        assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+    }
+
+    @Test
+    public void shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsInterruptedException() throws Exception {
+        stub(this.repositorySource.getConnection()).toThrow(new InterruptedException("sorry"));
+        assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+    }
+
+    @Test
+    public void shouldConsiderSourceToNotBeAvailabilityWhenGetConnectionThrowsAnyException() throws Exception {
+        stub(this.repositorySource.getConnection()).toThrow(new NullPointerException("sorry"));
+        assertThat(source.isAvailable(1, TimeUnit.SECONDS), is(false));
+    }
+
+    @Test
+    public void shouldConsiderEqualAnyFederatedSourcesWithSameName() {
+        RepositorySource repositorySource2 = mock(RepositorySource.class);
+        FederatedSource source2 = new FederatedSource(repositorySource2);
+
+        String theName = "Some name";
+        stub(repositorySource.getName()).toReturn(theName);
+        stub(repositorySource2.getName()).toReturn(theName);
+        assertThat(source.equals(source2), is(true));
+    }
+
+    @Test
+    public void shouldNotConsiderEqualAnyFederatedSourcesWithDifferentNames() {
+        RepositorySource repositorySource2 = mock(RepositorySource.class);
+        FederatedSource source2 = new FederatedSource(repositorySource2);
+
+        String theName = "Some name";
+        stub(repositorySource.getName()).toReturn(theName + " ");
+        stub(repositorySource2.getName()).toReturn(theName);
+        assertThat(source.equals(source2), is(false));
+
+        stub(repositorySource.getName()).toReturn(theName.toLowerCase());
+        stub(repositorySource2.getName()).toReturn(theName.toUpperCase());
+        assertThat(source.equals(source2), is(false));
+    }
+
+}


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




More information about the dna-commits mailing list