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
+ */
+@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
+ */
+@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
+ */
+@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
+ */
+@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
*/
+@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