DNA SVN: r321 - in trunk: dna-repository/src/test/java/org/jboss/dna/repository/federation and 3 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-06-30 17:45:21 -0400 (Mon, 30 Jun 2008)
New Revision: 321
Added:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedNode.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRegion.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/RepositoryConnectionFactories.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/RepositorySourceManager.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederationServiceTest.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCompositeCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/BasicExecutionEnvironment.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/ExecutionEnvironments.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/AbstractValueFactories.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/DelegatingValueFactories.java
Log:
DNA-115: Create federation service - Completed another round of refactoring to simplify configuration that also allows distribution/clustering
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedNode.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedNode.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedNode.java 2008-06-30 21:45:21 UTC (rev 321)
@@ -0,0 +1,140 @@
+/*
+ * 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.Iterator;
+import java.util.Set;
+import java.util.UUID;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Property;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public interface FederatedNode {
+ /**
+ * Get the unique identifier for this federated node.
+ *
+ * @return the UUID; never null
+ */
+ UUID getUuid();
+
+ /**
+ * Get the name of this node.
+ *
+ * @return the node name; never null
+ */
+ Name getName();
+
+ /**
+ * Get the property with the given name.
+ *
+ * @param propertyName the property name
+ * @return the property, or null if the property does not exist
+ * @throws IllegalArgumentException if the name is null
+ */
+ Property getProperty( Name propertyName );
+
+ /**
+ * Get the number of properties on this node. This value is technically an estimate, as it may not exactly match the number of
+ * properties returned by {@link #getProperties()} or {@link #getPropertyNames()}.
+ *
+ * @return the approximate number of properties.
+ */
+ int getPropertyCount();
+
+ /**
+ * Get the properties. This method returns a consistent set of properties at the moment this method is called, and is not
+ * affected by additions or change to the properties. In other words, it is safe for concurrent operations and is not a
+ * fail-fast iterator.
+ *
+ * @return the properties on this node via an immutable iterator
+ */
+ Iterator<Property> getProperties();
+
+ /**
+ * Get the names of the properties for this node. This method returns a consistent set of names at the moment this method is
+ * called, and is not affected by additions or change to the properties. In other words, it is safe for concurrent operations
+ * and is not a fail-fast iterator.
+ *
+ * @return the property names via an immutable iterator
+ */
+ Iterator<Name> getPropertyNames();
+
+ /**
+ * Set the property if it is not already set.
+ *
+ * @param property the property
+ * @return the existing property, or null if there was no property and the supplied property was set
+ * @throws IllegalArgumentException if the property is null
+ */
+ Property setPropertyIfAbsent( Property property );
+
+ /**
+ * Set the supplied properties. This method will overwrite any existing properties with the new properties if they have the
+ * same {@link Property#getName() property name}. This method ignores any null property references, and does nothing if there
+ * are no properties supplied.
+ *
+ * @param properties the properties that should be set
+ */
+ void setProperties( Property... properties );
+
+ /**
+ * Set the supplied properties. This method will overwrite any existing properties with the new properties if they have the
+ * same {@link Property#getName() property name}. This method ignores any null property references, and does nothing if there
+ * are no properties supplied.
+ *
+ * @param properties the properties that should be set
+ */
+ void setProperties( Iterable<Property> properties );
+
+ /**
+ * Replace all existing properties with the supplied properties. This method ignores any null property references, and does
+ * nothing if there are no properties supplied.
+ *
+ * @param properties the properties that should be set
+ */
+ void setAllProperties( Property... properties );
+
+ /**
+ * Replace all existing properties with the supplied properties. This method ignores any null property references, and does
+ * nothing if there are no properties supplied.
+ *
+ * @param properties the properties that should replace the existing properties
+ */
+ void setAllProperties( Iterable<Property> properties );
+
+ /**
+ * Remove all properties, except for the {@link #getName() name} and {@link #getUuid() identifier}.
+ */
+ void removeAllProperties();
+
+ /**
+ * Get the sources that have contributed information to this node.
+ *
+ * @return the names of the sources that have contributed content to this node.
+ */
+ Set<String> getContributingSources();
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRegion.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRegion.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRegion.java 2008-06-30 21:45:21 UTC (rev 321)
@@ -0,0 +1,188 @@
+/*
+ * 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 net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.repository.RepositoryI18n;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+
+/**
+ * A binding of content from a source into a particular location within a repository. The content in the source is defined by the
+ * name of the source and the {@link #getPathInSource() path within the source}. The {@link #getPathInRepository() path in the
+ * repository} defines the location at which the content appears.
+ * <p>
+ * Note that it is possible for a federated repository to have a single source may be bound to multiple locations, and multiple
+ * sources bound to the same location.
+ * </p>
+ *
+ * @author Randall Hauch
+ */
+@Immutable
+public class FederatedRegion implements Comparable<FederatedRegion> {
+
+ private final Path pathInRepository;
+ private final Path pathInSource;
+ private final String sourceName;
+
+ /**
+ * Create a binding given a location in the repository below which the content from the named source appears.
+ *
+ * @param pathInRepository the absolute path in the repository at which the content appears
+ * @param pathInSource the path in the source defining the content
+ * @param sourceName the name of the source
+ * @throws IllegalArgumentException if any of the parameters is null, or if the source name is empty/blank, or if the
+ * <code>pathInRepository</code> is not {@link Path#isAbsolute() absolute}.
+ */
+ public FederatedRegion( Path pathInRepository,
+ Path pathInSource,
+ String sourceName ) {
+ ArgCheck.isNotNull(pathInRepository, "pathInRepository");
+ ArgCheck.isNotNull(pathInSource, "pathInSource");
+ ArgCheck.isNotEmpty(sourceName, "sourceName");
+ if (!pathInRepository.isAbsolute()) {
+ String msg = RepositoryI18n.repositoryPathInFederationBindingIsNotAbsolute.text(pathInRepository.getString());
+ throw new IllegalArgumentException(msg);
+ }
+ this.pathInRepository = pathInRepository;
+ this.pathInSource = pathInSource;
+ this.sourceName = sourceName;
+ }
+
+ /**
+ * Get the location in the repository at which the source's content appears.
+ *
+ * @return the repository-based path for the top of the source's content
+ */
+ public Path getPathInRepository() {
+ return pathInRepository;
+ }
+
+ /**
+ * Get the path to the source content that is bound to the {@link #getPathInRepository() repository location}. This path is
+ * source-specific, and may be either absolute or relative.
+ *
+ * @return pathInSource
+ */
+ public Path getPathInSource() {
+ return pathInSource;
+ }
+
+ /**
+ * @return sourceName
+ */
+ public String getSourceName() {
+ return sourceName;
+ }
+
+ /**
+ * Convert a path defined in the source system into an equivalent path in the repository system.
+ *
+ * @param pathInSource the path in the source system, which may include the {@link #getPathInSource()}
+ * @param factory the path factory; may not be null
+ * @return the path in the repository system, which will be normalized and absolute (including the
+ * {@link #getPathInRepository()})
+ */
+ public Path convertPathInSourceToPathInRepository( Path pathInSource,
+ PathFactory factory ) {
+ Path relativeSourcePath = pathInSource;
+ if (this.pathInSource.isAncestorOf(pathInSource)) {
+ // Remove the leading source path ...
+ relativeSourcePath = pathInSource.relativeTo(this.pathInSource);
+ }
+ // Prepend the region's root path ...
+ Path result = factory.create(this.pathInRepository, relativeSourcePath);
+ return result.getNormalizedPath();
+ }
+
+ /**
+ * Convert a path defined in the repository system into an equivalent path in the source system.
+ *
+ * @param pathInRepository the path in the repository system, which may include the {@link #getPathInRepository()}
+ * @param factory the path factory; may not be null
+ * @return the path in the source system, which will be normalized and absolute (including the {@link #getPathInSource()})
+ */
+ public Path convertPathInRepositoryToPathInSource( Path pathInRepository,
+ PathFactory factory ) {
+ Path pathInRegion = pathInRepository;
+ if (this.pathInRepository.isAncestorOf(pathInRepository)) {
+ // Find the relative path from the root of this region ...
+ pathInRegion = pathInRepository.relativeTo(this.pathInRepository);
+ }
+ // Prepend the path in source ...
+ Path result = factory.create(this.pathInSource, pathInRegion);
+ return result.getNormalizedPath();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return pathInRepository.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof FederatedRegion) {
+ FederatedRegion that = (FederatedRegion)obj;
+ if (!this.getPathInRepository().equals(that.getPathInRepository())) return false;
+ if (!this.getPathInSource().equals(that.getPathInSource())) return false;
+ if (!this.getSourceName().equals(that.getSourceName())) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo( FederatedRegion that ) {
+ if (this == that) return 0;
+ int diff = this.getPathInRepository().compareTo(that.getPathInRepository());
+ if (diff != 0) return diff;
+ diff = this.getPathInSource().compareTo(that.getPathInSource());
+ if (diff != 0) return diff;
+ return this.getSourceName().compareTo(that.getSourceName());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return this.getPathInRepository().toString() + " -> \"" + this.getSourceName() + "\":" + this.getPathInSource();
+ }
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/RepositoryConnectionFactories.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/RepositoryConnectionFactories.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/RepositoryConnectionFactories.java 2008-06-30 21:45:21 UTC (rev 321)
@@ -0,0 +1,33 @@
+/*
+ * 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 org.jboss.dna.spi.graph.connection.RepositoryConnectionFactory;
+
+/**
+ * @author Randall Hauch
+ */
+public interface RepositoryConnectionFactories {
+
+ RepositoryConnectionFactory getConnectionFactory( String sourceName );
+
+}
Added: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/RepositorySourceManager.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/RepositorySourceManager.java (rev 0)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/RepositorySourceManager.java 2008-06-30 21:45:21 UTC (rev 321)
@@ -0,0 +1,341 @@
+/*
+ * 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.Collection;
+import java.util.Collections;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+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.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactory;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionPool;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+
+/**
+ * @author Randall Hauch
+ */
+public class RepositorySourceManager implements RepositoryConnectionFactories {
+
+ /**
+ * 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);
+ RepositorySourceManager.this.start();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doShutdown( State fromState ) {
+ super.doShutdown(fromState);
+ RepositorySourceManager.this.shutdown();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean awaitTermination( long timeout,
+ TimeUnit unit ) throws InterruptedException {
+ return RepositorySourceManager.this.awaitTermination(timeout, unit);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean doCheckIsTerminated() {
+ return RepositorySourceManager.this.isTerminated();
+ }
+
+ }
+
+ private final ServiceAdministrator administrator = new Administrator();
+ private final Lock sourcesWriteLock = new ReentrantLock();
+ private final ConcurrentMap<String, RepositorySource> sources = new ConcurrentHashMap<String, RepositorySource>();
+ private RepositoryConnectionFactories delegate;
+
+ /**
+ * Create a new manager instance.
+ *
+ * @param delegate the factories object that this instance should delegate to in the event that a source is not found in this
+ * manager; may be null if there is no delegate
+ */
+ public RepositorySourceManager( RepositoryConnectionFactories delegate ) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * @return delegate
+ */
+ public RepositoryConnectionFactories getDelegate() {
+ return delegate;
+ }
+
+ /**
+ * @param delegate Sets delegate to the specified value.
+ */
+ public void setDelegate( RepositoryConnectionFactories delegate ) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * @return administrator
+ */
+ public ServiceAdministrator getAdministrator() {
+ return this.administrator;
+ }
+
+ /**
+ * Utility method called by the administrator.
+ */
+ protected void start() {
+ // Do not establish connections to the sources; these will be established as needed
+
+ }
+
+ /**
+ * Utility method called by the administrator.
+ */
+ protected void shutdown() {
+ // Close all connections to the sources. This is done inside the sources write lock.
+ try {
+ this.sourcesWriteLock.lock();
+ for (RepositorySource source : this.sources.values()) {
+ if (source instanceof RepositoryConnectionPool) {
+ RepositoryConnectionPool pool = (RepositoryConnectionPool)source;
+ pool.shutdown();
+ }
+ }
+ } finally {
+ this.sourcesWriteLock.unlock();
+ }
+ }
+
+ /**
+ * Utility method called by the administrator.
+ *
+ * @param timeout
+ * @param unit
+ * @return true if all pools were terminated in the supplied time (or were already terminated), or false if the timeout
+ * occurred before all the connections were closed
+ * @throws InterruptedException
+ */
+ 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 (RepositorySource source : this.sources.values()) {
+ if (source instanceof RepositoryConnectionPool) {
+ RepositoryConnectionPool pool = (RepositoryConnectionPool)source;
+ if (!pool.awaitTermination(timeout, unit)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ } finally {
+ this.sourcesWriteLock.unlock();
+ }
+ }
+
+ /**
+ * Returns true if this federated repository is in the process of terminating after {@link ServiceAdministrator#shutdown()}
+ * has been called on the {@link #getAdministrator() administrator}, but the federated repository has connections that have
+ * not yet normally been {@link RepositoryConnection#close() closed}. This method may be useful for debugging. A return of
+ * <tt>true</tt> reported a sufficient period after shutdown may indicate that connection users have ignored or suppressed
+ * interruption, causing this repository not to properly terminate.
+ *
+ * @return true if terminating but not yet terminated, or false otherwise
+ * @see #isTerminated()
+ */
+ public boolean isTerminating() {
+ try {
+ this.sourcesWriteLock.lock();
+ for (RepositorySource source : this.sources.values()) {
+ if (source instanceof RepositoryConnectionPool) {
+ RepositoryConnectionPool pool = (RepositoryConnectionPool)source;
+ if (pool.isTerminating()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ } finally {
+ this.sourcesWriteLock.unlock();
+ }
+ }
+
+ /**
+ * Return true if this federated repository has completed its termination and no longer has any open connections.
+ *
+ * @return true if terminated, or false otherwise
+ * @see #isTerminating()
+ */
+ public boolean isTerminated() {
+ try {
+ this.sourcesWriteLock.lock();
+ for (RepositorySource source : this.sources.values()) {
+ if (source instanceof RepositoryConnectionPool) {
+ RepositoryConnectionPool pool = (RepositoryConnectionPool)source;
+ if (!pool.isTerminated()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ } finally {
+ this.sourcesWriteLock.unlock();
+ }
+ }
+
+ /**
+ * Get an unmodifiable collection of {@link RepositorySource federated sources}.
+ * <p>
+ * This method can safely be called while the federation repository is in use.
+ * </p>
+ *
+ * @return the sources
+ */
+ public Collection<RepositorySource> getSources() {
+ return Collections.unmodifiableCollection(this.sources.values());
+ }
+
+ /**
+ * 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( RepositorySource source ) {
+ if (source == null) return false;
+ try {
+ this.sourcesWriteLock.lock();
+ for (RepositorySource existingSource : this.sources.values()) {
+ if (existingSource.getName().equals(source.getName())) return false;
+ }
+ this.sources.put(source.getName(), 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( RepositorySource 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 RepositorySource removeSource( String name,
+ long timeToAwait,
+ TimeUnit unit ) throws InterruptedException {
+ try {
+ this.sourcesWriteLock.lock();
+ RepositorySource existingSource = this.sources.remove(name);
+ if (existingSource != null) {
+ // Shut down the connection pool if it is one ...
+ if (existingSource instanceof RepositoryConnectionPool) {
+ RepositoryConnectionPool pool = (RepositoryConnectionPool)existingSource;
+ pool.shutdown();
+ if (timeToAwait > 0l) pool.awaitTermination(timeToAwait, unit);
+ }
+ }
+ return existingSource;
+ } finally {
+ this.sourcesWriteLock.unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.repository.federation.RepositoryConnectionFactories#getConnectionFactory(java.lang.String)
+ */
+ public RepositoryConnectionFactory getConnectionFactory( String sourceName ) {
+ RepositoryConnectionFactory result = this.sources.get(sourceName);
+ if (result == null) {
+ RepositoryConnectionFactories delegate = this.delegate;
+ if (delegate != null) {
+ result = delegate.getConnectionFactory(sourceName);
+ }
+ }
+ return result;
+ }
+
+}
Added: trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederationServiceTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederationServiceTest.java (rev 0)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederationServiceTest.java 2008-06-30 21:45:21 UTC (rev 321)
@@ -0,0 +1,87 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.repository.federation;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.stub;
+import org.jboss.dna.repository.util.ExecutionContext;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.impl.BasicNamespaceRegistry;
+import org.jboss.dna.spi.graph.impl.StandardValueFactories;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class FederationServiceTest {
+
+ private FederationService service;
+ private FederatedRegion configRegion;
+ private StandardValueFactories valueFactories;
+ private PathFactory pathFactory;
+ private String configSourceName;
+ @Mock
+ private ExecutionContext env;
+ @Mock
+ private RepositorySourceManager sources;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ configSourceName = "configSource";
+ valueFactories = new StandardValueFactories(new BasicNamespaceRegistry());
+ pathFactory = valueFactories.getPathFactory();
+ Path pathInRepository = pathFactory.create("/dna:system");
+ Path pathInSource = pathFactory.create("/some/root");
+ configRegion = new FederatedRegion(pathInRepository, pathInSource, configSourceName);
+ stub(env.getValueFactories()).toReturn(valueFactories);
+ service = new FederationService(sources, configRegion, env, null);
+ }
+
+ @Ignore
+ @Test
+ public void shouldHaveServiceAdministratorAfterInstantiation() {
+ assertThat(service.getAdministrator(), is(notNullValue()));
+ }
+
+ @Ignore
+ @Test
+ public void shouldHaveConfigurationRegionAfterInstantiation() {
+ assertThat(service.getConfigurationRegion(), is(notNullValue()));
+ assertThat(service.getConfigurationRegion(), is(sameInstance(configRegion)));
+ }
+
+ @Ignore
+ @Test
+ public void shouldHaveNonNullClassLoaderFactoryAfterInstantiatingWithNullClassLoaderFactoryReference() {
+ assertThat(service.getClassLoaderFactory(), is(notNullValue()));
+ }
+
+}
Added: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCompositeCommand.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCompositeCommand.java (rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicCompositeCommand.java 2008-06-30 21:45:21 UTC (rev 321)
@@ -0,0 +1,71 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.commands.impl;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.jboss.dna.spi.graph.commands.CompositeCommand;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+
+/**
+ * @author Randall Hauch
+ */
+public class BasicCompositeCommand extends BasicGraphCommand implements CompositeCommand {
+
+ private final List<GraphCommand> commands = new ArrayList<GraphCommand>();
+
+ public BasicCompositeCommand() {
+ super();
+ }
+
+ public boolean isEmpty() {
+ return commands.isEmpty();
+ }
+
+ public int size() {
+ return commands.size();
+ }
+
+ public void add( GraphCommand command ) {
+ if (command != null) commands.add(command);
+ }
+
+ public GraphCommand getCommand( int index ) {
+ return commands.get(index);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Iterable#iterator()
+ */
+ public Iterator<GraphCommand> iterator() {
+ return commands.iterator();
+ }
+
+ public BasicCompositeCommand clearCommands() {
+ this.commands.clear();
+ return this;
+ }
+
+}
Added: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/BasicExecutionEnvironment.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/BasicExecutionEnvironment.java (rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/BasicExecutionEnvironment.java 2008-06-30 21:45:21 UTC (rev 321)
@@ -0,0 +1,78 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.connection;
+
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.spi.graph.NamespaceRegistry;
+import org.jboss.dna.spi.graph.PropertyFactory;
+import org.jboss.dna.spi.graph.ValueFactories;
+import org.jboss.dna.spi.graph.impl.BasicNamespaceRegistry;
+import org.jboss.dna.spi.graph.impl.BasicPropertyFactory;
+import org.jboss.dna.spi.graph.impl.StandardValueFactories;
+
+/**
+ * @author Randall Hauch
+ */
+public class BasicExecutionEnvironment implements ExecutionEnvironment {
+
+ private final PropertyFactory propertyFactory;
+ private final ValueFactories valueFactories;
+ private final NamespaceRegistry namespaceRegistry;
+
+ public BasicExecutionEnvironment() {
+ this(new BasicNamespaceRegistry());
+ }
+
+ public BasicExecutionEnvironment( NamespaceRegistry namespaceRegistry ) {
+ this(namespaceRegistry, null, null);
+ }
+
+ public BasicExecutionEnvironment( NamespaceRegistry namespaceRegistry,
+ ValueFactories valueFactories,
+ PropertyFactory propertyFactory ) {
+ ArgCheck.isNotNull(namespaceRegistry, "namespace registry");
+ this.namespaceRegistry = namespaceRegistry;
+ this.valueFactories = valueFactories != null ? valueFactories : new StandardValueFactories(this.namespaceRegistry);
+ this.propertyFactory = propertyFactory != null ? propertyFactory : new BasicPropertyFactory(this.valueFactories);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NamespaceRegistry getNamespaceRegistry() {
+ return this.namespaceRegistry;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ValueFactories getValueFactories() {
+ return this.valueFactories;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyFactory getPropertyFactory() {
+ return this.propertyFactory;
+ }
+}
Added: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/ExecutionEnvironments.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/ExecutionEnvironments.java (rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/ExecutionEnvironments.java 2008-06-30 21:45:21 UTC (rev 321)
@@ -0,0 +1,184 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.connection;
+
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.spi.graph.NameFactory;
+import org.jboss.dna.spi.graph.NamespaceRegistry;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.PropertyFactory;
+import org.jboss.dna.spi.graph.ValueFactories;
+import org.jboss.dna.spi.graph.impl.DelegatingValueFactories;
+
+/**
+ * Utility methods for creating various execution environments with replacement factories or components.
+ *
+ * @author Randall Hauch
+ */
+public class ExecutionEnvironments {
+
+ /**
+ * Create an environment that can be used to replace the supplied environment but that uses the supplied path factory.
+ *
+ * @param env the base environment
+ * @param pathFactory the new path factory
+ * @return the new execution environment
+ * @throws IllegalArgumentException if the environment or factory references are null
+ */
+ public static ExecutionEnvironment replace( ExecutionEnvironment env,
+ PathFactory pathFactory ) {
+ ArgCheck.isNotNull(env, "env");
+ ArgCheck.isNotNull(pathFactory, "pathFactory");
+ return new DelegatingExecutionEnvironment(env, null, null, null, pathFactory);
+ }
+
+ /**
+ * Create an environment that can be used to replace the supplied environment but that uses the supplied name factory.
+ *
+ * @param env the base environment
+ * @param nameFactory the new name factory
+ * @return the new execution environment
+ * @throws IllegalArgumentException if the environment or factory references are null
+ */
+ public static ExecutionEnvironment replace( ExecutionEnvironment env,
+ NameFactory nameFactory ) {
+ ArgCheck.isNotNull(env, "env");
+ ArgCheck.isNotNull(nameFactory, "nameFactory");
+ return new DelegatingExecutionEnvironment(env, null, null, nameFactory, null);
+ }
+
+ /**
+ * Create an environment that can be used to replace the supplied environment but that uses the supplied name and path
+ * factories.
+ *
+ * @param env the base environment
+ * @param nameFactory the new name factory
+ * @param pathFactory the new path factory
+ * @return the new execution environment
+ * @throws IllegalArgumentException if the environment or factory references are null
+ */
+ public static ExecutionEnvironment replace( ExecutionEnvironment env,
+ NameFactory nameFactory,
+ PathFactory pathFactory ) {
+ ArgCheck.isNotNull(env, "env");
+ ArgCheck.isNotNull(nameFactory, "nameFactory");
+ ArgCheck.isNotNull(pathFactory, "pathFactory");
+ return new DelegatingExecutionEnvironment(env, null, null, nameFactory, pathFactory);
+ }
+
+ /**
+ * Create an environment that can be used to replace the supplied environment but that uses the supplied namespace registry.
+ *
+ * @param env the base environment
+ * @param namespaceRegistry the new namespace registry
+ * @return the new execution environment
+ * @throws IllegalArgumentException if the environment or registry references are null
+ */
+ public static ExecutionEnvironment replace( ExecutionEnvironment env,
+ NamespaceRegistry namespaceRegistry ) {
+ ArgCheck.isNotNull(env, "env");
+ ArgCheck.isNotNull(namespaceRegistry, "namespaceRegistry");
+ return new DelegatingExecutionEnvironment(env, namespaceRegistry, null, null, null);
+ }
+
+ protected static class DelegatingExecutionEnvironment implements ExecutionEnvironment {
+
+ private final ExecutionEnvironment delegate;
+ private final NamespaceRegistry newNamespaceRegistry;
+ private final PropertyFactory newPropertyFactory;
+ private final ValueFactories newValueFactories;
+
+ public DelegatingExecutionEnvironment( ExecutionEnvironment delegate,
+ NamespaceRegistry newRegistry,
+ PropertyFactory newPropertyFactory,
+ ValueFactories newValueFactories ) {
+ assert delegate != null;
+ this.delegate = delegate;
+ this.newNamespaceRegistry = newRegistry;
+ this.newPropertyFactory = newPropertyFactory;
+ this.newValueFactories = newValueFactories;
+ }
+
+ public DelegatingExecutionEnvironment( ExecutionEnvironment delegate,
+ NamespaceRegistry newRegistry,
+ PropertyFactory newPropertyFactory,
+ final NameFactory newNameFactory,
+ final PathFactory newPathFactory ) {
+ assert delegate != null;
+ this.delegate = delegate;
+ this.newNamespaceRegistry = newRegistry;
+ this.newPropertyFactory = newPropertyFactory;
+ final PathFactory pathFactory = newPathFactory != null ? newPathFactory : delegate.getValueFactories().getPathFactory();
+ final NameFactory nameFactory = newNameFactory != null ? newNameFactory : delegate.getValueFactories().getNameFactory();
+ this.newValueFactories = newPathFactory == null ? null : new DelegatingValueFactories(delegate.getValueFactories()) {
+
+ @Override
+ public PathFactory getPathFactory() {
+ return pathFactory;
+ }
+
+ @Override
+ public NameFactory getNameFactory() {
+ return nameFactory;
+ }
+ };
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.ExecutionEnvironment#getNamespaceRegistry()
+ */
+ public NamespaceRegistry getNamespaceRegistry() {
+ if (newNamespaceRegistry != null) return newNamespaceRegistry;
+ return delegate.getNamespaceRegistry();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.ExecutionEnvironment#getPropertyFactory()
+ */
+ public PropertyFactory getPropertyFactory() {
+ if (newPropertyFactory != null) return newPropertyFactory;
+ return delegate.getPropertyFactory();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.ExecutionEnvironment#getValueFactories()
+ */
+ public ValueFactories getValueFactories() {
+ if (newValueFactories != null) return newValueFactories;
+ return delegate.getValueFactories();
+ }
+
+ /**
+ * @return delegate
+ */
+ protected ExecutionEnvironment getDelegate() {
+ return delegate;
+ }
+
+ }
+}
Added: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java (rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java 2008-06-30 21:45:21 UTC (rev 321)
@@ -0,0 +1,111 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.connection;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Randall Hauch
+ */
+public interface RepositoryConnectionPool extends RepositoryConnectionFactory {
+
+ /**
+ * Initiates an orderly shutdown in which connections that are currently in use are allowed to be used and closed as normal,
+ * but no new connections will be created. Invocation has no additional effect if already shut down.
+ * <p>
+ * Once the pool has been shutdown, it may not be used to {@link #getConnection() get connections}.
+ * </p>
+ *
+ * @throws SecurityException if a security manager exists and shutting down this pool may manipulate threads that the caller
+ * is not permitted to modify because it does not hold {@link java.lang.RuntimePermission}<tt>("modifyThread")</tt>,
+ * or the security manager's <tt>checkAccess</tt> method denies access.
+ * @see #shutdownNow()
+ */
+ void shutdown();
+
+ /**
+ * Attempts to close all connections, including those connections currently in use, and prevent the use of other connections.
+ *
+ * @throws SecurityException if a security manager exists and shutting down this pool may manipulate threads that the caller
+ * is not permitted to modify because it does not hold {@link java.lang.RuntimePermission}<tt>("modifyThread")</tt>,
+ * or the security manager's <tt>checkAccess</tt> method denies access.
+ * @see #shutdown()
+ */
+ void shutdownNow();
+
+ /**
+ * Return whether this connection pool is running and is able to {@link #getConnection() provide connections}. Note that this
+ * method is effectively <code>!isShutdown()</code>.
+ *
+ * @return true if this pool is running, or false otherwise
+ * @see #isShutdown()
+ * @see #isTerminated()
+ * @see #isTerminating()
+ */
+ boolean isRunning();
+
+ /**
+ * Return whether this connection pool is in the process of shutting down or has already been shut down. A result of
+ * <code>true</code> signals that the pool may no longer be used. Note that this method is effectively
+ * <code>!isRunning()</code>.
+ *
+ * @return true if this pool has been shut down, or false otherwise
+ * @see #isShutdown()
+ * @see #isTerminated()
+ * @see #isTerminating()
+ */
+ boolean isShutdown();
+
+ /**
+ * Returns true if this pool is in the process of terminating after {@link #shutdown()} or {@link #shutdownNow()} has been
+ * called but has not completely terminated. This method may be useful for debugging. A return of <tt>true</tt> reported a
+ * sufficient period after shutdown may indicate that submitted tasks have ignored or suppressed interruption, causing this
+ * executor not to properly terminate.
+ *
+ * @return true if terminating but not yet terminated, or false otherwise
+ * @see #isTerminated()
+ */
+ boolean isTerminating();
+
+ /**
+ * Return true if this pool has completed its termination and no longer has any open connections.
+ *
+ * @return true if terminated, or false otherwise
+ * @see #isTerminating()
+ */
+ boolean isTerminated();
+
+ /**
+ * Method that can be called after {@link #shutdown()} or {@link #shutdownNow()} to wait until all connections in use at the
+ * time those methods were called have been closed normally. This method accepts a maximum time duration, after which it will
+ * return even if all connections have not been closed.
+ *
+ * @param timeout the maximum time to wait for all connections to be closed and returned to the pool
+ * @param unit the time unit for <code>timeout</code>
+ * @return true if the pool was terminated in the supplied time (or was already terminated), or false if the timeout occurred
+ * before all the connections were closed
+ * @throws InterruptedException if the thread was interrupted
+ */
+ boolean awaitTermination( long timeout,
+ TimeUnit unit ) throws InterruptedException;
+
+}
Added: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/AbstractValueFactories.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/AbstractValueFactories.java (rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/AbstractValueFactories.java 2008-06-30 21:45:21 UTC (rev 321)
@@ -0,0 +1,130 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.impl;
+
+import java.util.Iterator;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.spi.graph.PropertyType;
+import org.jboss.dna.spi.graph.ValueFactories;
+import org.jboss.dna.spi.graph.ValueFactory;
+
+/**
+ * Abstract implementation of {@link ValueFactories} that implements all the methods other than the <code>get*Factory()</code>
+ * methods. Subclasses can simply implement these methods and inherit the {@link #iterator()}, {@link #getValueFactory(Object)}
+ * and {@link #getValueFactory(PropertyType)} method implementations.
+ *
+ * @author Randall Hauch
+ */
+public abstract class AbstractValueFactories implements ValueFactories {
+
+ /**
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ * <p>
+ * This implementation always iterates over the instances return by the <code>get*Factory()</code> methods.
+ * </p>
+ */
+ public Iterator<ValueFactory<?>> iterator() {
+ return new ValueFactoryIterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ValueFactory<?> getValueFactory( PropertyType type ) {
+ ArgCheck.isNotNull(type, "type");
+ switch (type) {
+ case BINARY:
+ return getBinaryFactory();
+ case BOOLEAN:
+ return getBooleanFactory();
+ case DATE:
+ return getDateFactory();
+ case DECIMAL:
+ return getDecimalFactory();
+ case DOUBLE:
+ return getDoubleFactory();
+ case LONG:
+ return getLongFactory();
+ case NAME:
+ return getNameFactory();
+ case OBJECT:
+ return getObjectFactory();
+ case PATH:
+ return getPathFactory();
+ case REFERENCE:
+ return getReferenceFactory();
+ case STRING:
+ return getStringFactory();
+ case URI:
+ return getUriFactory();
+ }
+ return getObjectFactory();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ValueFactory<?> getValueFactory( Object prototype ) {
+ ArgCheck.isNotNull(prototype, "prototype");
+ PropertyType inferredType = PropertyType.discoverType(prototype);
+ assert inferredType != null;
+ return getValueFactory(inferredType);
+ }
+
+ protected class ValueFactoryIterator implements Iterator<ValueFactory<?>> {
+ private final Iterator<PropertyType> propertyTypeIter = PropertyType.iterator();
+
+ protected ValueFactoryIterator() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.util.Iterator#hasNext()
+ */
+ public boolean hasNext() {
+ return propertyTypeIter.hasNext();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.util.Iterator#next()
+ */
+ public ValueFactory<?> next() {
+ PropertyType nextType = propertyTypeIter.next();
+ return getValueFactory(nextType);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.util.Iterator#remove()
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+}
Added: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/DelegatingValueFactories.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/DelegatingValueFactories.java (rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/DelegatingValueFactories.java 2008-06-30 21:45:21 UTC (rev 321)
@@ -0,0 +1,94 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.impl;
+
+import java.math.BigDecimal;
+import java.net.URI;
+import org.jboss.dna.spi.graph.Binary;
+import org.jboss.dna.spi.graph.DateTimeFactory;
+import org.jboss.dna.spi.graph.NameFactory;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.Reference;
+import org.jboss.dna.spi.graph.ValueFactories;
+import org.jboss.dna.spi.graph.ValueFactory;
+
+/**
+ * @author Randall Hauch
+ */
+public class DelegatingValueFactories extends AbstractValueFactories {
+
+ private final ValueFactories delegate;
+
+ protected DelegatingValueFactories( ValueFactories delegate ) {
+ assert delegate != null;
+ this.delegate = delegate;
+ }
+
+ public ValueFactory<Binary> getBinaryFactory() {
+ return delegate.getBinaryFactory();
+ }
+
+ public ValueFactory<Boolean> getBooleanFactory() {
+ return delegate.getBooleanFactory();
+ }
+
+ public DateTimeFactory getDateFactory() {
+ return delegate.getDateFactory();
+ }
+
+ public ValueFactory<BigDecimal> getDecimalFactory() {
+ return delegate.getDecimalFactory();
+ }
+
+ public ValueFactory<Double> getDoubleFactory() {
+ return delegate.getDoubleFactory();
+ }
+
+ public ValueFactory<Long> getLongFactory() {
+ return delegate.getLongFactory();
+ }
+
+ public NameFactory getNameFactory() {
+ return delegate.getNameFactory();
+ }
+
+ public ValueFactory<Object> getObjectFactory() {
+ return delegate.getObjectFactory();
+ }
+
+ public PathFactory getPathFactory() {
+ return delegate.getPathFactory();
+ }
+
+ public ValueFactory<Reference> getReferenceFactory() {
+ return delegate.getReferenceFactory();
+ }
+
+ public ValueFactory<String> getStringFactory() {
+ return delegate.getStringFactory();
+ }
+
+ public ValueFactory<URI> getUriFactory() {
+ return delegate.getUriFactory();
+ }
+
+}
15 years, 9 months
DNA SVN: r320 - in trunk: dna-repository/src/main/java/org/jboss/dna/repository and 9 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-06-30 17:42:54 -0400 (Mon, 30 Jun 2008)
New Revision: 320
Added:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/BasicRepositoryConnectionPool.java
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/BasicRepositoryConnectionPoolTest.java
Removed:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPoolTest.java
Modified:
trunk/
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SimpleExecutionContext.java
trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties
trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryTest.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathFactory.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PropertyType.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetPropertiesCommand.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperation.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperations.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/PathValueFactory.java
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/StandardValueFactories.java
trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositorySourceLoadHarness.java
Log:
DNA-115: Create federation service - Completed another round of refactoring to simplify configuration that also allows distribution/clustering
Property changes on: trunk
___________________________________________________________________
Name: svn:ignore
- target
+ .metadata
target
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-30 21:34:41 UTC (rev 319)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryI18n.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -31,6 +31,7 @@
*/
public final class RepositoryI18n {
+ // Services and Repository
public static I18n invalidStateString;
public static I18n serviceShutdowAndMayNotBeStarted;
public static I18n serviceShutdowAndMayNotBePaused;
@@ -45,6 +46,7 @@
public static I18n errorFindingPropertyNameInPropertyChangedEvent;
public static I18n errorFindingPropertyNameInPropertyRemovedEvent;
+ // Rules
public static I18n unableToObtainJsr94RuleAdministrator;
public static I18n errorUsingJsr94RuleAdministrator;
public static I18n unableToObtainJsr94ServiceProvider;
@@ -66,6 +68,7 @@
public static I18n observationServiceName;
public static I18n ruleServiceName;
+ // Sequencing
public static I18n sequencingServiceName;
public static I18n unableToChangeExecutionContextWhileRunning;
public static I18n unableToStartSequencingServiceWithoutExecutionContext;
@@ -80,6 +83,7 @@
public static I18n sequencingPropertyOnNode;
public static I18n writingOutputSequencedFromPropertyOnNodes;
+ // Properties
public static I18n errorReadingPropertiesFromContainerNode;
public static I18n requiredPropertyOnNodeWasExpectedToBeStringValue;
public static I18n optionalPropertyOnNodeWasExpectedToBeStringValue;
@@ -95,14 +99,20 @@
public static I18n errorGettingNodeRelativeToNode;
public static I18n unknownPropertyValueType;
+ // Path expressions
public static I18n pathExpressionIsInvalid;
public static I18n pathExpressionMayNotBeBlank;
public static I18n pathExpressionHasInvalidSelect;
public static I18n pathExpressionHasInvalidMatch;
+ // Observation
public static I18n errorUnregisteringWorkspaceListenerWhileShuttingDownObservationService;
+ // General
public static I18n invalidRepositoryNodePath;
+ public static I18n unableToLoadClassUsingClasspath;
+ public static I18n unableToInstantiateClassUsingClasspath;
+ public static I18n unableToAccessClassUsingClasspath;
// XML Sequencer
public static I18n errorSequencingXmlDocument;
@@ -114,9 +124,11 @@
public static I18n interruptedWhileConnectingToFederationConfigurationRepository;
public static I18n interruptedWhileUsingFederationConfigurationRepository;
public static I18n interruptedWhileClosingConnectionToFederationConfigurationRepository;
+ public static I18n unableToFindRepositorySourceByName;
public static I18n unableToCreateConnectionToFederatedRepository;
public static I18n unableToAuthenticateConnectionToFederatedRepository;
public static I18n repositoryHasBeenShutDown;
+ public static I18n repositoryPathInFederationBindingIsNotAbsolute;
static {
try {
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepository.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -25,21 +25,20 @@
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.ExecutionEnvironment;
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.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
+ * a set of {@link RepositorySource federated sources}, and provides the logic of interacting with those sources and presenting a
* single unified graph.
*
* @author Randall Hauch
@@ -96,35 +95,32 @@
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 ExecutionEnvironment env;
+ private final RepositoryConnectionFactories connectionFactories;
+ private final CopyOnWriteArrayList<FederatedRegion> regions = new CopyOnWriteArrayList<FederatedRegion>();
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
+ * @param repositoryName the name of the repository
+ * @param env the execution environment
+ * @param connectionFactories the set of connection factories that should be used
+ * @throws IllegalArgumentException if any of the parameters are null, or if the name is blank
*/
- public FederatedRepository( FederationService service,
- String name ) {
- ArgCheck.isNotNull(service, "service");
- ArgCheck.isNotEmpty(name, "name");
- this.name = name;
- this.service = service;
+ public FederatedRepository( String repositoryName,
+ ExecutionEnvironment env,
+ RepositoryConnectionFactories connectionFactories ) {
+ ArgCheck.isNotNull(connectionFactories, "connectionFactories");
+ ArgCheck.isNotNull(env, "env");
+ ArgCheck.isNotEmpty(repositoryName, "repositoryName");
+ this.name = repositoryName;
+ this.env = env;
+ this.connectionFactories = connectionFactories;
}
/**
- * @return service
- */
- protected FederationService getService() {
- return this.service;
- }
-
- /**
* Get the name of this repository
*
* @return name
@@ -141,9 +137,25 @@
}
/**
+ * @return the execution environment
+ */
+ public ExecutionEnvironment getExecutionEnvironment() {
+ return env;
+ }
+
+ /**
+ * @return connectionFactories
+ */
+ protected RepositoryConnectionFactories getConnectionFactories() {
+ return connectionFactories;
+ }
+
+ /**
* Utility method called by the administrator.
*/
protected void startRepository() {
+ // Look for the sources in the repository, creating any that are missing
+ // Look for the
// Do not establish connections to the sources; these will be established as needed
}
@@ -152,17 +164,7 @@
* 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);
+ // Connections to this repository check before doing anything with this, so no need to do anything to them ...
}
/**
@@ -176,18 +178,7 @@
*/
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();
- }
+ return true;
}
/**
@@ -201,17 +192,7 @@
* @see #isTerminated()
*/
public boolean isTerminating() {
- try {
- this.sourcesWriteLock.lock();
- for (FederatedSource source : this.sources) {
- if (source.getConnectionPool().isTerminating()) {
- return true;
- }
- }
- return false;
- } finally {
- this.sourcesWriteLock.unlock();
- }
+ return false;
}
/**
@@ -221,143 +202,36 @@
* @see #isTerminating()
*/
public boolean isTerminated() {
- try {
- this.sourcesWriteLock.lock();
- for (FederatedSource source : this.sources) {
- if (!source.getConnectionPool().isTerminated()) {
- return false;
- }
- }
- return true;
- } finally {
- this.sourcesWriteLock.unlock();
- }
+ return false;
}
/**
- * 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 unmodifiable list of bindings.
*
- * @return the sources
+ * @return the bindings
*/
- public List<FederatedSource> getSources() {
- return Collections.unmodifiableList(this.sources);
+ public List<FederatedRegion> getRegions() {
+ return Collections.unmodifiableList(regions);
}
/**
- * 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>
+ * Add the supplied federation region to this repository, if it is not already in the repository. . This method does not
+ * attempt to check whether this region would result in a duplicate region.
*
- * @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.
+ * @param region the region to be added
+ * @return true if the region was added, or false if there was already a duplicate region
+ * @throws IllegalArgumentException if the binding reference is null
*/
- 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;
+ protected boolean addRegionIfAbsent( FederatedRegion region ) {
+ ArgCheck.isNotNull(region, "region");
+ return this.regions.addIfAbsent(region);
}
- /**
- * 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;
+ protected boolean removeBinding( FederatedRegion region ) {
+ return this.regions.remove(region);
}
/**
- * 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.
*
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedRepositoryConnection.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -40,7 +40,8 @@
protected static final RepositorySourceListener NO_OP_LISTENER = new RepositorySourceListener() {
- public void notify( String sourceName, Object... events ) {
+ public void notify( String sourceName,
+ Object... events ) {
// do nothing
}
};
@@ -49,7 +50,8 @@
private final FederatedRepositorySource source;
private RepositorySourceListener listener = NO_OP_LISTENER;
- protected FederatedRepositoryConnection( FederatedRepository repository, FederatedRepositorySource source ) {
+ protected FederatedRepositoryConnection( FederatedRepository repository,
+ FederatedRepositorySource source ) {
assert source != null;
assert repository != null;
this.source = source;
@@ -106,14 +108,16 @@
/**
* {@inheritDoc}
*/
- public boolean ping( long time, TimeUnit unit ) {
+ public boolean ping( long time,
+ TimeUnit unit ) {
return this.repository.getAdministrator().isStarted();
}
/**
* {@inheritDoc}
*/
- public void execute( ExecutionEnvironment env, GraphCommand... commands ) throws RepositorySourceException {
+ public void execute( ExecutionEnvironment env,
+ GraphCommand... commands ) throws RepositorySourceException {
if (!this.repository.getAdministrator().isStarted()) {
throw new RepositorySourceException(RepositoryI18n.repositoryHasBeenShutDown.text(this.repository.getName()));
}
Deleted: trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederatedSource.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -1,146 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.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.RepositoryConnectionFactory;
-import org.jboss.dna.spi.graph.connection.RepositoryConnectionPool;
-import org.jboss.dna.spi.graph.connection.RepositorySource;
-import org.jboss.dna.spi.graph.connection.RepositorySourceException;
-
-/**
- * A component that represents a {@link RepositorySource repository source} (with its state) being federated in a
- * {@link FederatedRepository}.
- *
- * @author Randall Hauch
- */
-@ThreadSafe
-public class FederatedSource implements RepositoryConnectionFactory {
-
- private final RepositorySource source;
- private final RepositoryConnectionPool connectionPool;
-
- public FederatedSource( RepositorySource source ) {
- ArgCheck.isNotNull(source, "source");
- this.source = source;
- this.connectionPool = new RepositoryConnectionPool(source);
- }
-
- protected FederatedSource( RepositorySource source, RepositoryConnectionPool connectionPool ) {
- ArgCheck.isNotNull(source, "source");
- this.source = source;
- this.connectionPool = connectionPool;
- }
-
- /**
- * Get the name for this federated repository source.
- *
- * @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;
- }
-
- /**
- * {@inheritDoc}
- */
- public RepositoryConnection getConnection() throws RepositorySourceException, InterruptedException {
- return this.connectionPool.getConnection();
- }
-
- /**
- * Determine whether the federated source is available by attempting to connect to the source and
- * {@link RepositoryConnection#ping(long, TimeUnit) pinging} the source.
- *
- * @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;
- }
-
-}
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-30 21:34:41 UTC (rev 319)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/federation/FederationService.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -21,22 +21,40 @@
*/
package org.jboss.dna.repository.federation;
+import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
+import java.util.List;
+import java.util.Map;
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.collection.Problems;
+import org.jboss.dna.common.collection.SimpleProblems;
import org.jboss.dna.common.component.ClassLoaderFactory;
import org.jboss.dna.common.component.StandardClassLoaderFactory;
import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.Reflection;
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.repository.util.ExecutionContext;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.NameFactory;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.ValueFactories;
+import org.jboss.dna.spi.graph.ValueFactory;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.commands.impl.BasicCompositeCommand;
+import org.jboss.dna.spi.graph.commands.impl.BasicGetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.impl.BasicGetNodeCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositoryConnectionFactory;
import org.jboss.dna.spi.graph.connection.RepositorySource;
/**
@@ -45,6 +63,9 @@
@ThreadSafe
public class FederationService implements AdministeredService {
+ protected static final String CLASSNAME_PROPERTY_NAME = "dna:classname";
+ protected static final String CLASSPATH_PROPERTY_NAME = "dna:classpath";
+
/**
* The administrative component for this service.
*
@@ -92,8 +113,9 @@
}
private final ClassLoaderFactory classLoaderFactory;
- private final ExecutionContext executionContext;
- private final RepositorySource configurationSource;
+ private final ExecutionEnvironment env;
+ private final RepositorySourceManager sources;
+ private final FederatedRegion configurationRegion;
private final Administrator administrator = new Administrator();
private final ConcurrentMap<String, FederatedRepository> repositories = new ConcurrentHashMap<String, FederatedRepository>();
private RepositoryConnection configurationConnection;
@@ -101,22 +123,26 @@
/**
* Create a federation service instance
*
- * @param configurationSource the repository source that contains the configuration for this federation service (including the
- * respositories and the sources used by the federated repositories)
- * @param executionContext the context in which this service should run
+ * @param sources the source manager
+ * @param configurationRegion the repository region defining where the service can find configuration information for the
+ * different repositories that it is to manage
+ * @param env the execution environment in which this service should run
* @param classLoaderFactory the class loader factory used to instantiate {@link RepositorySource} instances; may be null if
* this instance should use a default factory that attempts to load classes first from the
* {@link Thread#getContextClassLoader() thread's current context class loader} and then from the class loader that
* loaded this class.
* @throws IllegalArgumentException if the bootstrap source is null or the execution context is null
*/
- public FederationService( RepositorySource configurationSource,
- ExecutionContext executionContext,
+ public FederationService( RepositorySourceManager sources,
+ FederatedRegion configurationRegion,
+ ExecutionEnvironment env,
ClassLoaderFactory classLoaderFactory ) {
- ArgCheck.isNotNull(configurationSource, "configurationSource");
- ArgCheck.isNotNull(executionContext, "executionContext");
- this.configurationSource = configurationSource;
- this.executionContext = executionContext;
+ ArgCheck.isNotNull(configurationRegion, "configurationRegion");
+ ArgCheck.isNotNull(sources, "sources");
+ ArgCheck.isNotNull(env, "env");
+ this.sources = sources;
+ this.configurationRegion = configurationRegion;
+ this.env = env;
this.classLoaderFactory = classLoaderFactory != null ? classLoaderFactory : new StandardClassLoaderFactory();
}
@@ -128,22 +154,27 @@
}
/**
- * Get the source for the repository containing the configuration for this federation service.
- *
- * @return the configuration repository source; never null
+ * @return configurationRegion
*/
- public RepositorySource getConfigurationSource() {
- return this.configurationSource;
+ public FederatedRegion getConfigurationRegion() {
+ return configurationRegion;
}
/**
- * @return executionContext
+ * @return sources
*/
- public ExecutionContext getExecutionContext() {
- return this.executionContext;
+ public RepositorySourceManager getRepositorySourceManager() {
+ return sources;
}
/**
+ * @return env
+ */
+ public ExecutionEnvironment getExecutionEnvironment() {
+ return env;
+ }
+
+ /**
* @return classLoaderFactory
*/
public ClassLoaderFactory getClassLoaderFactory() {
@@ -157,115 +188,137 @@
protected synchronized void startService() {
if (this.configurationConnection == null) {
+ Problems problems = new SimpleProblems();
+
+ // ------------------------------------------------------------------------------------
+ // Establish a connection to the configuration source ...
+ // ------------------------------------------------------------------------------------
+ final String configurationSourceName = configurationRegion.getSourceName();
+ RepositoryConnectionFactory factory = sources.getConnectionFactory(configurationSourceName);
+ if (factory == null) {
+ I18n msg = RepositoryI18n.unableToFindRepositorySourceByName;
+ throw new FederationException(msg.text(configurationSourceName));
+ }
try {
- this.configurationConnection = this.configurationSource.getConnection();
+ this.configurationConnection = factory.getConnection();
} catch (InterruptedException err) {
I18n msg = RepositoryI18n.interruptedWhileConnectingToFederationConfigurationRepository;
- throw new FederationException(msg.text(configurationSource.getName()));
+ throw new FederationException(msg.text(configurationSourceName));
}
- // // Read the configuration and obtain the RepositorySource instances for each of the
- // // federated repositories. Each repository configuration is rooted at
- // // "/dna:repositories/[repositoryName]", and under this node at "dna:federation"
- // // is the RepositorySource for the integrated repository, and under the
- // // "dna:sources/[sourceName]" are the nodes representing the inital RepositorySource
- // // instances for each of the sources.
- // //
- // // The integrated repository for each federated repository contains the complete unified
- // // graph merged from all of the sources. It also contains the configuration for the federated
- // // repository at "/dna:system/dna:federation", including under "dna:sources" a node for each of the current
- // // sources (e.g., "/dna:system/dna:federation/dna:sources/[sourceName]"). If this area of the
- // // graph does not yet exist, the sources are copied from the
- // // "/dna:repositories/[repositoryName]/dna:sources" area of the service's configuration repository.
- // // However, after that, the federated repository manages its own sources.
- //
- // ValueFactories valueFactories = executionContext.getValueFactories();
- // PathFactory pathFactory = valueFactories.getPathFactory();
- //
- // // Get the list of repositories in the configuration, and create a FederatedRepository for each one ...
- // try {
- // Path repositoriesNode = pathFactory.create("dna:repositories");
- // BasicGetChildrenCommand getRepositories = new BasicGetChildrenCommand(repositoriesNode);
- // configurationConnection.execute(executionContext, getRepositories);
- //
- // // For each repository ...
- // for (Path.Segment child : getRepositories.getChildren()) {
- //
- // // Get the repository's name ...
- // final String repositoryName = child.getUnencodedString();
- // final Path pathToRepository = pathFactory.create(repositoriesNode, child);
- //
- // // Record the initial sources ...
- // final Path.Segment sourcesSegment = pathFactory.createSegment("dna:sources");
- // final Path pathToRepositorySourcesNode = pathFactory.create(pathToRepository, sourcesSegment);
- // BasicRecordBranchCommand getSources = new BasicRecordBranchCommand(pathToRepositorySourcesNode,
- // NodeConflictBehavior.DO_NOT_REPLACE);
- //
- // // Get the source of the integrated repository ...
- // final Path.Segment integratedRepositorySegment = pathFactory.createSegment("dna:federatedRepository");
- // final Path pathToIntegratedRepositoryNode = pathFactory.create(pathToRepository, integratedRepositorySegment);
- // BasicGetNodeCommand getSource = new BasicGetNodeCommand(pathToIntegratedRepositoryNode);
- // configurationConnection.execute(executionContext, getSource);
- // RepositorySource integratedRepositorySource = createRepositorySource(valueFactories,
- // getSource.getProperties());
- //
- // // Copy these to the federated repository ...
- // RepositoryConnection integratedConnection = integratedReposi
- // // Look for the
- // // Read the initial sources ...
- //
- // // Get the repository source information for the integrated repository ...
- //
- // // Look for existing sources and load them ...
- //
- // // Otherwise, read the intial sources from the
- //
- // }
- // } catch (InterruptedException err) {
- // I18n msg = RepositoryI18n.interruptedWhileUsingFederationConfigurationRepository;
- // throw new FederationException(msg.text(configurationSource.getName()));
- // }
- // // TODO
+
+ // ------------------------------------------------------------------------------------
+ // Read the configuration ...
+ // ------------------------------------------------------------------------------------
+ ValueFactories valueFactories = env.getValueFactories();
+ PathFactory pathFactory = valueFactories.getPathFactory();
+
+ // Read the configuration and the repository sources, located as child nodes/branches under "/dna:sources",
+ // and then instantiate and register each in the "sources" manager
+ try {
+ Path sourcesNode = pathFactory.create("/dna:sources");
+ BasicGetChildrenCommand getSources = new BasicGetChildrenCommand(sourcesNode);
+ configurationConnection.execute(env, getSources);
+
+ // Build the commands to get each of the children ...
+ List<Path.Segment> children = getSources.getChildren();
+ if (children.isEmpty()) {
+ BasicCompositeCommand commands = new BasicCompositeCommand();
+ for (Path.Segment child : getSources.getChildren()) {
+ final Path pathToSource = pathFactory.create(sourcesNode, child);
+ commands.add(new BasicGetNodeCommand(pathToSource));
+ }
+ configurationConnection.execute(env, commands);
+
+ // Iterate over each source node obtained ...
+ for (GraphCommand command : commands) {
+ BasicGetNodeCommand getSourceCommand = (BasicGetNodeCommand)command;
+ RepositorySource source = createRepositorySource(getSourceCommand.getPath(),
+ getSourceCommand.getProperties(),
+ problems);
+ if (source != null) sources.addSource(source);
+ }
+ }
+ } catch (InterruptedException err) {
+ I18n msg = RepositoryI18n.interruptedWhileUsingFederationConfigurationRepository;
+ throw new FederationException(msg.text(configurationSourceName));
+ }
+
}
}
- // protected RepositorySource createRepositorySource( ValueFactories values,
- // Iterable<Property> properties ) {
- // // Put the properties in a map so we can find them by name ...
- // Map<Name, Property> byName = new HashMap<Name, Property>();
- // for (Property property : properties) {
- // byName.put(property.getName(), property);
- // }
- //
- // // Get the concrete class ...
- // Name classnameName = values.getNameFactory().create("dna:className");
- // Property classProperty = byName.get(classnameName);
- // if (classProperty == null) return null;
- // if (classProperty.isEmpty()) return null;
- // String className = values.getStringFactory().create(classProperty.getValues().next());
- // if (className == null) return null;
- //
- // Name classpathName = values.getNameFactory().create("dna:classpath");
- // Property classpathProperty = byName.get(classpathName);
- // String[] classpath = null;
- // if (classpathProperty != null) {
- // classpath = values.getStringFactory().create(classpathProperty.getValuesAsArray());
- // }
- //
- // // Load the class and look for the constructors ...
- // RepositorySource source = null;
- // try {
- // ClassLoader loader = getClassLoaderFactory().getClassLoader(classpath);
- // Class<?> sourceClass = loader.loadClass(className);
- // source = (RepositorySource)sourceClass.newInstance();
- // } catch (ClassNotFoundException err) {
- // return null;
- // } catch (InstantiationException err) {
- //
- // } catch (IllegalAccessException err) {
- // }
- // return null;
- // }
+ /**
+ * Instantiate the {@link RepositorySource} described by the supplied properties.
+ *
+ * @param path the path to the node where these properties were found; never null
+ * @param properties the properties; never null
+ * @param problems the problems container in which any problems should be reported; never null
+ * @return the repository source instance, or null if it could not be created
+ */
+ @SuppressWarnings( "null" )
+ protected RepositorySource createRepositorySource( Path path,
+ Map<Name, Property> properties,
+ Problems problems ) {
+ ValueFactories valueFactories = env.getValueFactories();
+ NameFactory nameFactory = valueFactories.getNameFactory();
+ ValueFactory<String> stringFactory = valueFactories.getStringFactory();
+ // Get the classname and classpath ...
+ Property classnameProperty = properties.get(nameFactory.create(CLASSNAME_PROPERTY_NAME));
+ Property classpathProperty = properties.get(nameFactory.create(CLASSPATH_PROPERTY_NAME));
+ if (classnameProperty == null) {
+ problems.addError(RepositoryI18n.requiredPropertyIsMissingFromNode, CLASSNAME_PROPERTY_NAME, path);
+ }
+ if (classpathProperty == null) {
+ problems.addError(RepositoryI18n.requiredPropertyIsMissingFromNode, CLASSPATH_PROPERTY_NAME, path);
+ }
+ if (problems.hasErrors()) return null;
+
+ // Create the instance ...
+ String classname = stringFactory.create(classnameProperty.getValues().next());
+ String[] classpath = stringFactory.create(classpathProperty.getValuesAsArray());
+ ClassLoader classLoader = this.classLoaderFactory.getClassLoader(classpath);
+ RepositorySource source = null;
+ try {
+ Class<?> sourceClass = classLoader.loadClass(classname);
+ source = (RepositorySource)sourceClass.newInstance();
+ } catch (ClassNotFoundException err) {
+ problems.addError(err, RepositoryI18n.unableToLoadClassUsingClasspath, classname, classpath);
+ } catch (IllegalAccessException err) {
+ problems.addError(err, RepositoryI18n.unableToAccessClassUsingClasspath, classname, classpath);
+ } catch (Throwable err) {
+ problems.addError(err, RepositoryI18n.unableToInstantiateClassUsingClasspath, classname, classpath);
+ }
+
+ // Now set all the properties that we can, ignoring any property that doesn't fit pattern ...
+ Reflection reflection = new Reflection(source.getClass());
+ for (Map.Entry<Name, Property> entry : properties.entrySet()) {
+ Name propertyName = entry.getKey();
+ Property property = entry.getValue();
+ String javaPropertyName = propertyName.getLocalName();
+ if (property.isEmpty()) continue;
+ Object value = null;
+ if (property.isSingle()) {
+ value = property.getValues().next();
+ } else if (property.isMultiple()) {
+ value = property.getValuesAsArray();
+ }
+ try {
+ reflection.invokeSetterMethodOnTarget(javaPropertyName, source, value);
+ } catch (SecurityException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (NoSuchMethodException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (IllegalArgumentException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (IllegalAccessException err) {
+ // Do nothing ... assume not a JavaBean property
+ } catch (InvocationTargetException err) {
+ // Do nothing ... assume not a JavaBean property
+ }
+ }
+ return source;
+ }
+
/**
* Get the federated repository object with the given name. The resulting repository will be started and ready to use.
*
@@ -273,14 +326,17 @@
* @return the repository instance
*/
protected FederatedRepository getRepository( String name ) {
+ if (this.configurationConnection == null) startService();
+
// 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 ..
+ // // New up a repository and configure it ...
+ // Repository
+ repository = new FederatedRepository(name, env, sources);
+ // Now register it, being careful to not overwrite any added since "get" call above ..
FederatedRepository existingRepository = this.repositories.putIfAbsent(name, repository);
if (existingRepository != null) repository = existingRepository;
}
@@ -294,8 +350,8 @@
try {
this.configurationConnection.close();
} catch (InterruptedException err) {
- throw new FederationException(
- RepositoryI18n.interruptedWhileClosingConnectionToFederationConfigurationRepository.text(this.configurationSource.getName()));
+ I18n msg = RepositoryI18n.interruptedWhileClosingConnectionToFederationConfigurationRepository;
+ throw new FederationException(msg.text(configurationRegion.getSourceName()));
}
// Now shut down all repositories ...
for (String repositoryName : this.repositories.keySet()) {
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SimpleExecutionContext.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SimpleExecutionContext.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/util/SimpleExecutionContext.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -25,19 +25,15 @@
import org.jboss.dna.spi.graph.NamespaceRegistry;
import org.jboss.dna.spi.graph.PropertyFactory;
import org.jboss.dna.spi.graph.ValueFactories;
-import org.jboss.dna.spi.graph.impl.BasicPropertyFactory;
-import org.jboss.dna.spi.graph.impl.StandardValueFactories;
+import org.jboss.dna.spi.graph.connection.BasicExecutionEnvironment;
/**
* @author Randall Hauch
*/
-public class SimpleExecutionContext implements ExecutionContext {
+public class SimpleExecutionContext extends BasicExecutionEnvironment implements ExecutionContext {
private final JcrTools tools = new JcrTools();
- private final PropertyFactory propertyFactory;
private final SessionFactory sessionFactory;
- private final ValueFactories valueFactories;
- private final NamespaceRegistry namespaceRegistry;
public SimpleExecutionContext( SessionFactory sessionFactory,
String repositoryWorkspaceForNamespaceRegistry ) {
@@ -53,38 +49,14 @@
NamespaceRegistry namespaceRegistry,
ValueFactories valueFactories,
PropertyFactory propertyFactory ) {
+ super(namespaceRegistry, valueFactories, propertyFactory);
ArgCheck.isNotNull(sessionFactory, "session factory");
- ArgCheck.isNotNull(namespaceRegistry, "namespace registry");
this.sessionFactory = sessionFactory;
- this.namespaceRegistry = namespaceRegistry;
- this.valueFactories = valueFactories != null ? valueFactories : new StandardValueFactories(this.namespaceRegistry);
- this.propertyFactory = propertyFactory != null ? propertyFactory : new BasicPropertyFactory(this.valueFactories);
}
/**
* {@inheritDoc}
*/
- public NamespaceRegistry getNamespaceRegistry() {
- return this.namespaceRegistry;
- }
-
- /**
- * {@inheritDoc}
- */
- public ValueFactories getValueFactories() {
- return this.valueFactories;
- }
-
- /**
- * {@inheritDoc}
- */
- public PropertyFactory getPropertyFactory() {
- return this.propertyFactory;
- }
-
- /**
- * {@inheritDoc}
- */
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
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-30 21:34:41 UTC (rev 319)
+++ trunk/dna-repository/src/main/resources/org/jboss/dna/repository/RepositoryI18n.properties 2008-06-30 21:42:54 UTC (rev 320)
@@ -91,6 +91,9 @@
errorUnregisteringWorkspaceListenerWhileShuttingDownObservationService = Error unregistering workspace listener while shutting down observation service
invalidRepositoryNodePath = The repository node path "{0}" is not valid: {1}
+unableToLoadClassUsingClasspath = Unable to load class "{0}" using classpath "{1}"
+unableToInstantiateClassUsingClasspath = Unable to instantiate class "{0}" using classpath "{1}"
+unableToAccessClassUsingClasspath = Unable to access class "{0}" using classpath "{1}"
errorSequencingXmlDocument = An error was received while sequencing XML: {0}
fatalErrorSequencingXmlDocument = A fatal error was received while sequencing XML: {0}
@@ -101,6 +104,8 @@
interruptedWhileConnectingToFederationConfigurationRepository = Interrupted while connecting to federation configuration repository "{0}"
interruptedWhileUsingFederationConfigurationRepository = Interrupted while using federation configuration repository "{0}"
interruptedWhileClosingConnectionToFederationConfigurationRepository = Interrupted while closing connection to federation configuration repository "{0}"
+unableToFindRepositorySourceByName = Unable to find the repository source "{0}"
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.
+repositoryPathInFederationBindingIsNotAbsolute = The repository path in a federation binding must be absolute, but was "{0}"
Modified: trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryTest.java
===================================================================
--- trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryTest.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedRepositoryTest.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -27,13 +27,9 @@
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.hasItems;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import java.util.concurrent.TimeUnit;
-import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.BasicExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
-import org.jboss.dna.spi.graph.connection.TimeDelayingRepositorySource;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
@@ -44,28 +40,24 @@
*/
public class FederatedRepositoryTest {
+ private ExecutionEnvironment env;
private FederatedRepository repository;
private String name;
@Mock
- private FederationService service;
- @Mock
private RepositorySourceListener listener1;
@Mock
private RepositorySourceListener listener2;
@Mock
- private FederatedSource source1;
- @Mock
- private FederatedSource source2;
+ private RepositoryConnectionFactories connectionFactories;
- // private RepositoryConnectionPool connectionPool;
+ // private BasicRepositoryConnectionPool connectionPool;
@Before
public void beforeEach() {
MockitoAnnotations.initMocks(this);
+ env = new BasicExecutionEnvironment();
name = "Test repository";
- repository = new FederatedRepository(service, name);
- stub(source1.getName()).toReturn("soure 1");
- stub(source2.getName()).toReturn("soure 2");
+ repository = new FederatedRepository(name, env, connectionFactories);
}
@Test
@@ -74,11 +66,6 @@
}
@Test
- public void shouldHaveFederationServicePassedIntoConstructor() {
- assertThat(repository.getService(), is(sameInstance(service)));
- }
-
- @Test
public void shouldHaveAdministrator() {
assertThat(repository.getAdministrator(), is(notNullValue()));
}
@@ -150,73 +137,32 @@
}
@Test
- public void shouldHaveNoSourcesAfterInitialization() {
- assertThat(repository.getSources(), is(notNullValue()));
- assertThat(repository.getSources().isEmpty(), is(true));
+ public void shouldHaveNoFederationRegionsAfterInitialization() {
+ assertThat(repository.getRegions(), is(notNullValue()));
+ assertThat(repository.getRegions().isEmpty(), is(true));
}
@Test
- public void shouldAddSourceThatIsNotAlreadyRegistered() {
- assertThat(repository.getSources(), hasItems(new FederatedSource[] {}));
- assertThat(repository.addSource(source1), is(true));
- assertThat(repository.getSources(), hasItems(source1));
- assertThat(repository.addSource(source2), is(true));
- assertThat(repository.getSources(), hasItems(source1, source2));
+ public void shouldAddFederationRegionThatIsNotAlreadyRegistered() {
+ FederatedRegion region1 = mock(FederatedRegion.class);
+ FederatedRegion region2 = mock(FederatedRegion.class);
+
+ assertThat(repository.getRegions().isEmpty(), is(true));
+ assertThat(repository.addRegionIfAbsent(region1), is(true));
+ assertThat(repository.getRegions(), hasItems(region1));
+ assertThat(repository.addRegionIfAbsent(region2), is(true));
+ assertThat(repository.getRegions(), hasItems(region1, region2));
}
@Test
public void shouldNotAddSourceThatIsAlreadyRegistered() {
- String source1Name = source1.getName();
- FederatedSource source1a = mock(FederatedSource.class);
- stub(source1a.getName()).toReturn(source1Name);
+ FederatedRegion region1 = mock(FederatedRegion.class);
- assertThat(repository.getSources(), hasItems(new FederatedSource[] {}));
- assertThat(repository.addSource(source1), is(true));
- assertThat(repository.getSources(), hasItems(source1));
- assertThat(repository.addSource(source2), is(true));
- assertThat(repository.getSources(), hasItems(source1, source2));
- assertThat(repository.addSource(source1a), is(false));
- assertThat(repository.getSources(), hasItems(source1, source2));
+ assertThat(repository.getRegions().isEmpty(), is(true));
+ assertThat(repository.addRegionIfAbsent(region1), is(true));
+ assertThat(repository.getRegions(), hasItems(region1));
+ assertThat(repository.addRegionIfAbsent(region1), is(false));
+ assertThat(repository.getRegions(), hasItems(region1));
}
- @Test
- public void shouldShutdownAndRemoveRepositoryFromFederationService() {
- repository.getAdministrator().shutdown();
- verify(service, times(1)).removeRepository(repository);
- }
-
- @Test
- public void shouldShutdownAllSourceConnectionPoolsWhenShuttingDownRepository() throws Exception {
- // Create the source instances that wait during termination ...
- TimeDelayingRepositorySource timeDelaySource1 = new TimeDelayingRepositorySource("time delay source 1");
- source1 = new FederatedSource(timeDelaySource1);
- TimeDelayingRepositorySource timeDelaySource2 = new TimeDelayingRepositorySource("time delay source 2");
- source2 = new FederatedSource(timeDelaySource2);
- repository.addSource(source1);
- repository.addSource(source2);
- assertThat(repository.getSources(), hasItems(source1, source2));
-
- // Get a connection from one source ...
- RepositoryConnection connection = source2.getConnection();
- assertThat(connection, is(notNullValue()));
-
- // Shut down the repository, which will shut down each of the sources ...
- repository.getAdministrator().shutdown();
- assertThat(repository.getAdministrator().isShutdown(), is(true));
- assertThat(repository.getAdministrator().isTerminated(), is(false));
-
- // Source 1 should be shut down AND terminated ...
- assertThat(source1.getConnectionPool().isShutdown(), is(true));
- assertThat(source1.getConnectionPool().isTerminated(), is(true));
-
- // Source 2 should be shutdown but not terminated, since we still have a connection ...
- assertThat(source2.getConnectionPool().isShutdown(), is(true));
- assertThat(source2.getConnectionPool().isTerminated(), is(false));
-
- // Close the connection ...
- connection.close();
- assertThat(repository.getAdministrator().awaitTermination(1, TimeUnit.SECONDS), is(true));
- assertThat(repository.getAdministrator().isShutdown(), is(true));
- assertThat(repository.getAdministrator().isTerminated(), is(true));
- }
}
Deleted: 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 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-repository/src/test/java/org/jboss/dna/repository/federation/FederatedSourceTest.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -1,179 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.repository.federation;
-
-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 java.util.concurrent.TimeUnit;
-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;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class FederatedSourceTest {
-
- private FederatedSource source;
- @Mock
- private RepositoryConnection connection;
- @Mock
- private RepositorySource repositorySource;
-
- /**
- * @throws java.lang.Exception
- */
- @Before
- public void beforeEach() throws Exception {
- MockitoAnnotations.initMocks(this);
- 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));
- }
-
-}
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathFactory.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathFactory.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PathFactory.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -87,6 +87,18 @@
Path createRelativePath( Path.Segment... segments );
/**
+ * Create a path by appending the supplied relative path to the supplied parent path. The resulting path will be
+ * {@link Path#isAbsolute() absolute} if the supplied parent path is absolute.
+ *
+ * @param parentPath the path that is to provide the basis for the new path
+ * @param childPath the path that should be appended to the parent path
+ * @return the new path
+ * @throws IllegalArgumentException if the parent path reference or the child path reference is null
+ */
+ Path create( Path parentPath,
+ Path childPath );
+
+ /**
* Create a path by appending the supplied names to the parent path.
*
* @param parentPath the path that is to provide the basis for the new path
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PropertyType.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PropertyType.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/PropertyType.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -23,8 +23,11 @@
import java.math.BigDecimal;
import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
+import java.util.List;
import net.jcip.annotations.Immutable;
import org.jboss.dna.spi.SpiI18n;
@@ -48,6 +51,15 @@
URI("URI", ValueComparators.URI_COMPARATOR, URI.class),
OBJECT("Object", ValueComparators.OBJECT_COMPARATOR, Object.class);
+ private static final List<PropertyType> ALL_PROPERTY_TYPES;
+ static {
+ List<PropertyType> types = new ArrayList<PropertyType>();
+ for (PropertyType type : PropertyType.values()) {
+ types.add(type);
+ }
+ ALL_PROPERTY_TYPES = Collections.unmodifiableList(types);
+ }
+
private final String name;
private final Comparator<?> comparator;
private final Class<?> valueClass;
@@ -101,4 +113,13 @@
}
return OBJECT;
}
+
+ /**
+ * Return an iterator over all the property type enumeration literals.
+ *
+ * @return an immutable iterator
+ */
+ public static Iterator<PropertyType> iterator() {
+ return ALL_PROPERTY_TYPES.iterator();
+ }
}
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetPropertiesCommand.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetPropertiesCommand.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/impl/BasicGetPropertiesCommand.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -67,10 +67,14 @@
*
* @return the map of property name to values
*/
- public Iterable<Property> getProperties() {
+ public Iterable<Property> getPropertyIterator() {
return this.properties.values();
}
+ public Map<Name, Property> getProperties() {
+ return this.properties;
+ }
+
/**
* {@inheritDoc}
*/
Copied: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/BasicRepositoryConnectionPool.java (from rev 307, trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java)
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/BasicRepositoryConnectionPool.java (rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/BasicRepositoryConnectionPool.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -0,0 +1,967 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.connection;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import javax.transaction.xa.XAResource;
+import net.jcip.annotations.GuardedBy;
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.spi.SpiI18n;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+
+/**
+ * @author Randall Hauch
+ */
+@ThreadSafe
+public class BasicRepositoryConnectionPool implements RepositoryConnectionPool {
+
+ /**
+ * The core pool size for default-constructed pools is {@value} .
+ */
+ public static final int DEFAULT_CORE_POOL_SIZE = 1;
+
+ /**
+ * The maximum pool size for default-constructed pools is {@value} .
+ */
+ public static final int DEFAULT_MAXIMUM_POOL_SIZE = 10;
+
+ /**
+ * The keep-alive time for connections in default-constructed pools is {@value} seconds.
+ */
+ public static final long DEFAULT_KEEP_ALIVE_TIME_IN_SECONDS = 30;
+
+ /**
+ * Permission for checking shutdown
+ */
+ private static final RuntimePermission shutdownPerm = new RuntimePermission("modifyThread");
+
+ /**
+ * The factory that this pool uses to create new connections.
+ */
+ private final RepositoryConnectionFactory connectionFactory;
+
+ /**
+ * Lock held on updates to poolSize, corePoolSize, maximumPoolSize, and workers set.
+ */
+ private final ReentrantLock mainLock = new ReentrantLock();
+
+ /**
+ * Wait condition to support awaitTermination
+ */
+ private final Condition termination = mainLock.newCondition();
+
+ /**
+ * Set containing all connections that are available for use.
+ */
+ @GuardedBy( "mainLock" )
+ private final BlockingQueue<ConnectionWrapper> availableConnections = new LinkedBlockingQueue<ConnectionWrapper>();
+
+ /**
+ * The connections that are currently in use.
+ */
+ @GuardedBy( "mainLock" )
+ private final Set<ConnectionWrapper> inUseConnections = new HashSet<ConnectionWrapper>();
+
+ /**
+ * Timeout in nanoseconds for idle connections waiting to be used. Threads use this timeout only when there are more than
+ * corePoolSize present. Otherwise they wait forever to be used.
+ */
+ private volatile long keepAliveTime;
+
+ /**
+ * The target pool size, updated only while holding mainLock, but volatile to allow concurrent readability even during
+ * updates.
+ */
+ @GuardedBy( "mainLock" )
+ private volatile int corePoolSize;
+
+ /**
+ * Maximum pool size, updated only while holding mainLock but volatile to allow concurrent readability even during updates.
+ */
+ @GuardedBy( "mainLock" )
+ private volatile int maximumPoolSize;
+
+ /**
+ * Current pool size, updated only while holding mainLock but volatile to allow concurrent readability even during updates.
+ */
+ @GuardedBy( "mainLock" )
+ private volatile int poolSize;
+
+ /**
+ * Lifecycle state, updated only while holding mainLock but volatile to allow concurrent readability even during updates.
+ */
+ @GuardedBy( "mainLock" )
+ private volatile int runState;
+
+ // Special values for runState
+ /** Normal, not-shutdown mode */
+ static final int RUNNING = 0;
+ /** Controlled shutdown mode */
+ static final int SHUTDOWN = 1;
+ /** Immediate shutdown mode */
+ static final int STOP = 2;
+ /** Final state */
+ static final int TERMINATED = 3;
+
+ /**
+ * Flag specifying whether a connection should be validated before returning it from the {@link #getConnection()} method.
+ */
+ private final AtomicBoolean validateConnectionBeforeUse = new AtomicBoolean(false);
+
+ /**
+ * The time in nanoseconds that ping should wait before timing out and failing.
+ */
+ private final AtomicLong pingTimeout = new AtomicLong(0);
+
+ /**
+ * The number of times an attempt to obtain a connection should fail with invalid connections before throwing an exception.
+ */
+ private final AtomicInteger maxFailedAttemptsBeforeError = new AtomicInteger(10);
+
+ private final AtomicLong totalConnectionsCreated = new AtomicLong(0);
+
+ private final AtomicLong totalConnectionsUsed = new AtomicLong(0);
+
+ private final Logger logger = Logger.getLogger(this.getClass());
+
+ /**
+ * Create the pool to use the supplied connection factory, which is typically a {@link RepositorySource}. This constructor
+ * uses the {@link #DEFAULT_CORE_POOL_SIZE default core pool size}, {@link #DEFAULT_MAXIMUM_POOL_SIZE default maximum pool
+ * size}, and {@link #DEFAULT_KEEP_ALIVE_TIME_IN_SECONDS default keep-alive time (in seconds)}.
+ *
+ * @param connectionFactory the factory for connections
+ * @throws IllegalArgumentException if the connection factory is null or any of the supplied arguments are invalid
+ */
+ public BasicRepositoryConnectionPool( RepositoryConnectionFactory connectionFactory ) {
+ this(connectionFactory, DEFAULT_CORE_POOL_SIZE, DEFAULT_MAXIMUM_POOL_SIZE, DEFAULT_KEEP_ALIVE_TIME_IN_SECONDS,
+ TimeUnit.SECONDS);
+ }
+
+ /**
+ * Create the pool to use the supplied connection factory, which is typically a {@link RepositorySource}.
+ *
+ * @param connectionFactory the factory for connections
+ * @param corePoolSize the number of connections to keep in the pool, even if they are idle.
+ * @param maximumPoolSize the maximum number of connections to allow in the pool.
+ * @param keepAliveTime when the number of connection is greater than the core, this is the maximum time that excess idle
+ * connections will be kept before terminating.
+ * @param unit the time unit for the keepAliveTime argument.
+ * @throws IllegalArgumentException if the connection factory is null or any of the supplied arguments are invalid
+ */
+ public BasicRepositoryConnectionPool( RepositoryConnectionFactory connectionFactory,
+ int corePoolSize,
+ int maximumPoolSize,
+ long keepAliveTime,
+ TimeUnit unit ) {
+ ArgCheck.isNonNegative(corePoolSize, "corePoolSize");
+ ArgCheck.isPositive(maximumPoolSize, "maximumPoolSize");
+ ArgCheck.isNonNegative(keepAliveTime, "keepAliveTime");
+ ArgCheck.isNotNull(connectionFactory, "repository connection factory");
+ if (maximumPoolSize < corePoolSize) {
+ throw new IllegalArgumentException(SpiI18n.maximumPoolSizeMayNotBeSmallerThanCorePoolSize.text());
+ }
+ this.connectionFactory = connectionFactory;
+ this.corePoolSize = corePoolSize;
+ this.maximumPoolSize = maximumPoolSize;
+ this.keepAliveTime = unit.toNanos(keepAliveTime);
+ this.setPingTimeout(100, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnectionFactory#getName()
+ */
+ public String getName() {
+ return this.connectionFactory.getName();
+ }
+
+ // -------------------------------------------------
+ // Property settings ...
+ // -------------------------------------------------
+
+ /**
+ * @return validateConnectionBeforeUse
+ */
+ public boolean getValidateConnectionBeforeUse() {
+ return this.validateConnectionBeforeUse.get();
+ }
+
+ /**
+ * @param validateConnectionBeforeUse Sets validateConnectionBeforeUse to the specified value.
+ */
+ public void setValidateConnectionBeforeUse( boolean validateConnectionBeforeUse ) {
+ this.validateConnectionBeforeUse.set(validateConnectionBeforeUse);
+ }
+
+ /**
+ * @return pingTimeout
+ */
+ public long getPingTimeoutInNanos() {
+ return this.pingTimeout.get();
+ }
+
+ /**
+ * @param pingTimeout the time to wait for a ping to complete
+ * @param unit the time unit of the time argument
+ */
+ public void setPingTimeout( long pingTimeout,
+ TimeUnit unit ) {
+ ArgCheck.isNonNegative(pingTimeout, "time");
+ this.pingTimeout.set(unit.toNanos(pingTimeout));
+ }
+
+ /**
+ * @return maxFailedAttemptsBeforeError
+ */
+ public int getMaxFailedAttemptsBeforeError() {
+ return this.maxFailedAttemptsBeforeError.get();
+ }
+
+ /**
+ * @param maxFailedAttemptsBeforeError Sets maxFailedAttemptsBeforeError to the specified value.
+ */
+ public void setMaxFailedAttemptsBeforeError( int maxFailedAttemptsBeforeError ) {
+ this.maxFailedAttemptsBeforeError.set(maxFailedAttemptsBeforeError);
+ }
+
+ /**
+ * Sets the time limit for which connections may remain idle before being closed. If there are more than the core number of
+ * connections currently in the pool, after waiting this amount of time without being used, excess threads will be terminated.
+ * This overrides any value set in the constructor.
+ *
+ * @param time the time to wait. A time value of zero will cause excess connections to terminate immediately after being
+ * returned.
+ * @param unit the time unit of the time argument
+ * @throws IllegalArgumentException if time less than zero
+ * @see #getKeepAliveTime
+ */
+ public void setKeepAliveTime( long time,
+ TimeUnit unit ) {
+ ArgCheck.isNonNegative(time, "time");
+ this.keepAliveTime = unit.toNanos(time);
+ }
+
+ /**
+ * Returns the connection keep-alive time, which is the amount of time which connections in excess of the core pool size may
+ * remain idle before being closed.
+ *
+ * @param unit the desired time unit of the result
+ * @return the time limit
+ * @see #setKeepAliveTime
+ */
+ public long getKeepAliveTime( TimeUnit unit ) {
+ assert unit != null;
+ return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * @return maximumPoolSize
+ */
+ public int getMaximumPoolSize() {
+ return this.maximumPoolSize;
+ }
+
+ /**
+ * Sets the maximum allowed number of connections. This overrides any value set in the constructor. If the new value is
+ * smaller than the current value, excess existing but unused connections will be closed.
+ *
+ * @param maximumPoolSize the new maximum
+ * @throws IllegalArgumentException if maximumPoolSize less than zero or the {@link #getCorePoolSize() core pool size}
+ * @see #getMaximumPoolSize
+ */
+ public void setMaximumPoolSize( int maximumPoolSize ) {
+ ArgCheck.isPositive(maximumPoolSize, "maximum pool size");
+ if (maximumPoolSize < corePoolSize) {
+ throw new IllegalArgumentException(SpiI18n.maximumPoolSizeMayNotBeSmallerThanCorePoolSize.text());
+ }
+ final ReentrantLock mainLock = this.mainLock;
+ try {
+ mainLock.lock();
+ int extra = this.maximumPoolSize - maximumPoolSize;
+ this.maximumPoolSize = maximumPoolSize;
+ if (extra > 0 && poolSize > maximumPoolSize) {
+ // Drain the extra connections from those available ...
+ drainUnusedConnections(extra);
+ }
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * Returns the core number of connections.
+ *
+ * @return the core number of connections
+ * @see #setCorePoolSize(int)
+ */
+ public int getCorePoolSize() {
+ return this.corePoolSize;
+ }
+
+ /**
+ * Sets the core number of connections. This overrides any value set in the constructor. If the new value is smaller than the
+ * current value, excess existing and unused connections will be closed. If larger, new connections will, if needed, be
+ * created.
+ *
+ * @param corePoolSize the new core size
+ * @throws RepositorySourceException if there was an error obtaining the new connection
+ * @throws InterruptedException if the thread was interrupted during the operation
+ * @throws IllegalArgumentException if <tt>corePoolSize</tt> less than zero
+ * @see #getCorePoolSize()
+ */
+ public void setCorePoolSize( int corePoolSize ) throws RepositorySourceException, InterruptedException {
+ ArgCheck.isNonNegative(corePoolSize, "core pool size");
+ if (maximumPoolSize < corePoolSize) {
+ throw new IllegalArgumentException(SpiI18n.maximumPoolSizeMayNotBeSmallerThanCorePoolSize.text());
+ }
+ final ReentrantLock mainLock = this.mainLock;
+ try {
+ mainLock.lock();
+ int extra = this.corePoolSize - corePoolSize;
+ this.corePoolSize = corePoolSize;
+ if (extra < 0) {
+ // Add connections ...
+ addConnectionsIfUnderCorePoolSize();
+ } else if (extra > 0 && poolSize > corePoolSize) {
+ // Drain the extra connections from those available ...
+ drainUnusedConnections(extra);
+ }
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ // -------------------------------------------------
+ // Statistics ...
+ // -------------------------------------------------
+
+ /**
+ * Returns the current number of connections in the pool, including those that are checked out (in use) and those that are not
+ * being used.
+ *
+ * @return the number of connections
+ */
+ public int getPoolSize() {
+ return poolSize;
+ }
+
+ /**
+ * Returns the approximate number of connections that are currently checked out from the pool.
+ *
+ * @return the number of checked-out connections
+ */
+ public int getInUseCount() {
+ final ReentrantLock mainLock = this.mainLock;
+ try {
+ mainLock.lock();
+ return this.inUseConnections.size();
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * Get the total number of connections that have been created by this pool.
+ *
+ * @return the total number of connections created by this pool
+ */
+ public long getTotalConnectionsCreated() {
+ return this.totalConnectionsCreated.get();
+ }
+
+ /**
+ * Get the total number of times connections have been {@link #getConnection()} used.
+ *
+ * @return the total number
+ */
+ public long getTotalConnectionsUsed() {
+ return this.totalConnectionsUsed.get();
+ }
+
+ // -------------------------------------------------
+ // State management methods ...
+ // -------------------------------------------------
+
+ /**
+ * Starts a core connection, causing it to idly wait for use. This overrides the default policy of starting core connections
+ * only when they are {@link #getConnection() needed}. This method will return <tt>false</tt> if all core connections have
+ * already been started.
+ *
+ * @return true if a connection was started
+ * @throws RepositorySourceException if there was an error obtaining the new connection
+ * @throws InterruptedException if the thread was interrupted during the operation
+ */
+ public boolean prestartCoreConnection() throws RepositorySourceException, InterruptedException {
+ final ReentrantLock mainLock = this.mainLock;
+ try {
+ mainLock.lock();
+ return addConnectionIfUnderCorePoolSize();
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * Starts all core connections, causing them to idly wait for use. This overrides the default policy of starting core
+ * connections only when they are {@link #getConnection() needed}.
+ *
+ * @return the number of connections started.
+ * @throws RepositorySourceException if there was an error obtaining the new connection
+ * @throws InterruptedException if the thread was interrupted during the operation
+ */
+ public int prestartAllCoreConnections() throws RepositorySourceException, InterruptedException {
+ final ReentrantLock mainLock = this.mainLock;
+ try {
+ mainLock.lock();
+ return addConnectionsIfUnderCorePoolSize();
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnectionPool#shutdown()
+ */
+ public void shutdown() {
+ // Fail if caller doesn't have modifyThread permission. We
+ // explicitly check permissions directly because we can't trust
+ // implementations of SecurityManager to correctly override
+ // the "check access" methods such that our documented
+ // security policy is implemented.
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) java.security.AccessController.checkPermission(shutdownPerm);
+
+ this.logger.debug("Shutting down repository connection pool for {0}", getName());
+ boolean fullyTerminated = false;
+ final ReentrantLock mainLock = this.mainLock;
+ try {
+ mainLock.lock();
+ int state = this.runState;
+ if (state == RUNNING) {
+ // don't override shutdownNow
+ this.runState = SHUTDOWN;
+ }
+
+ // Kill the maintenance thread ...
+
+ // Remove and close all available connections ...
+ if (!this.availableConnections.isEmpty()) {
+ // Drain the extra connections from those available ...
+ drainUnusedConnections(this.availableConnections.size());
+ }
+
+ // If there are no connections being used, trigger full termination now ...
+ if (this.inUseConnections.isEmpty()) {
+ fullyTerminated = true;
+ this.logger.trace("Signalling termination of repository connection pool for {0}", getName());
+ runState = TERMINATED;
+ termination.signalAll();
+ this.logger.debug("Terminated repository connection pool for {0}", getName());
+ }
+ // Otherwise the last connection that is closed will transition the runState to TERMINATED ...
+ } finally {
+ mainLock.unlock();
+ }
+ if (fullyTerminated) terminated();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnectionPool#shutdownNow()
+ */
+ public void shutdownNow() {
+ // Almost the same code as shutdown()
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) java.security.AccessController.checkPermission(shutdownPerm);
+
+ this.logger.debug("Shutting down (immediately) repository connection pool for {0}", getName());
+ boolean fullyTerminated = false;
+ final ReentrantLock mainLock = this.mainLock;
+ try {
+ mainLock.lock();
+ int state = this.runState;
+ if (state != TERMINATED) {
+ // don't override shutdownNow
+ this.runState = STOP;
+ }
+
+ // Kill the maintenance thread ...
+
+ // Remove and close all available connections ...
+ if (!this.availableConnections.isEmpty()) {
+ // Drain the extra connections from those available ...
+ drainUnusedConnections(this.availableConnections.size());
+ }
+
+ // If there are connections being used, close them now ...
+ if (!this.inUseConnections.isEmpty()) {
+ for (ConnectionWrapper connectionInUse : this.inUseConnections) {
+ try {
+ this.logger.trace("Closing repository connection to {0}", getName());
+ connectionInUse.getOriginal().close();
+ } catch (InterruptedException e) {
+ // Ignore this ...
+ }
+ }
+ this.poolSize -= this.inUseConnections.size();
+ // The last connection that is closed will transition the runState to TERMINATED ...
+ } else {
+ // There are no connections in use, so trigger full termination now ...
+ fullyTerminated = true;
+ this.logger.trace("Signalling termination of repository connection pool for {0}", getName());
+ runState = TERMINATED;
+ termination.signalAll();
+ this.logger.debug("Terminated repository connection pool for {0}", getName());
+ }
+
+ } finally {
+ mainLock.unlock();
+ }
+ if (fullyTerminated) terminated();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnectionPool#isRunning()
+ */
+ public boolean isRunning() {
+ return runState == RUNNING;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnectionPool#isShutdown()
+ */
+ public boolean isShutdown() {
+ return runState != RUNNING;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnectionPool#isTerminating()
+ */
+ public boolean isTerminating() {
+ return runState == STOP;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnectionPool#isTerminated()
+ */
+ public boolean isTerminated() {
+ return runState == TERMINATED;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryConnectionPool#awaitTermination(long, java.util.concurrent.TimeUnit)
+ */
+ public boolean awaitTermination( long timeout,
+ TimeUnit unit ) throws InterruptedException {
+ long nanos = unit.toNanos(timeout);
+ final ReentrantLock mainLock = this.mainLock;
+ try {
+ mainLock.lock();
+ for (;;) {
+ // this.logger.debug("---> Run state = {}; condition = {}", runState, termination);
+ if (runState == TERMINATED) return true;
+ if (nanos <= 0) return false;
+ nanos = termination.awaitNanos(nanos);
+ // this.logger.debug("---> Done waiting: run state = {}; condition = {}", runState, termination);
+ }
+ } finally {
+ mainLock.unlock();
+ }
+ }
+
+ /**
+ * Method invoked when the pool has terminated. Default implementation does nothing. Note: To properly nest multiple
+ * overridings, subclasses should generally invoke <tt>super.terminated</tt> within this method.
+ */
+ protected void terminated() {
+ }
+
+ /**
+ * Invokes <tt>shutdown</tt> when this pool is no longer referenced.
+ */
+ @Override
+ protected void finalize() {
+ shutdown();
+ }
+
+ // -------------------------------------------------
+ // Connection management methods ...
+ // -------------------------------------------------
+
+ /**
+ * {@inheritDoc}
+ */
+ public RepositoryConnection getConnection() throws RepositorySourceException, InterruptedException {
+ int attemptsAllowed = this.maxFailedAttemptsBeforeError.get();
+ ConnectionWrapper connection = null;
+ // Do this until we get a good connection ...
+ int attemptsRemaining = attemptsAllowed;
+ while (connection == null && attemptsRemaining > 0) {
+ --attemptsRemaining;
+ ReentrantLock mainLock = this.mainLock;
+ try {
+ mainLock.lock();
+ // If we're shutting down the pool, then just close the connection ...
+ if (this.runState != RUNNING) {
+ throw new IllegalStateException(SpiI18n.repositoryConnectionPoolIsNotRunning.text());
+ }
+ // If there are fewer total connections than the core size ...
+ if (this.poolSize < this.corePoolSize) {
+ // Immediately create a wrapped connection and return it ...
+ connection = newWrappedConnection();
+ }
+ // Peek to see if there is a connection available ...
+ else if (this.availableConnections.peek() != null) {
+ // There is, so take it and return it ...
+ connection = this.availableConnections.take();
+ }
+ // There is no connection available. If there are fewer total connections than the maximum size ...
+ else if (this.poolSize < this.maximumPoolSize) {
+ // Immediately create a wrapped connection and return it ...
+ connection = newWrappedConnection();
+ }
+ if (connection != null) {
+ this.inUseConnections.add(connection);
+ }
+ } finally {
+ mainLock.unlock();
+ }
+ if (connection == null) {
+ // There are not enough connections, so wait in line for the next available connection ...
+ this.logger.trace("Waiting for a repository connection from pool {0}", getName());
+ connection = this.availableConnections.take();
+ mainLock = this.mainLock;
+ mainLock.lock();
+ try {
+ if (connection != null) {
+ this.inUseConnections.add(connection);
+ }
+ } finally {
+ mainLock.unlock();
+ }
+ this.logger.trace("Recieved a repository connection from pool {0}", getName());
+ }
+ if (connection != null && this.validateConnectionBeforeUse.get()) {
+ connection = validateConnection(connection);
+ }
+ }
+ if (connection == null) {
+ // We were unable to obtain a usable connection, so fail ...
+ throw new RepositorySourceException(SpiI18n.unableToObtainValidRepositoryAfterAttempts.text(attemptsAllowed));
+ }
+ this.totalConnectionsUsed.incrementAndGet();
+ return connection;
+ }
+
+ /**
+ * This method is automatically called by the {@link ConnectionWrapper} when it is {@link ConnectionWrapper#close() closed}.
+ *
+ * @param wrapper the wrapper to the connection that is being returned to the pool
+ */
+ protected void returnConnection( ConnectionWrapper wrapper ) {
+ assert wrapper != null;
+ ConnectionWrapper wrapperToClose = null;
+ final ReentrantLock mainLock = this.mainLock;
+ try {
+ mainLock.lock();
+ // Remove the connection from the in-use set ...
+ boolean removed = this.inUseConnections.remove(wrapper);
+ assert removed;
+
+ // If we're shutting down the pool, then just close the connection ...
+ if (this.runState != RUNNING) {
+ wrapperToClose = wrapper;
+ }
+ // If there are more connections than the maximum size...
+ else if (this.poolSize > this.maximumPoolSize) {
+ // Immediately close this connection ...
+ wrapperToClose = wrapper;
+ }
+ // Attempt to make the connection available (this should generally work, unless there is an upper limit
+ // to the number of available connections) ...
+ else if (!this.availableConnections.offer(new ConnectionWrapper(wrapper.getOriginal()))) {
+ // The pool of available connection is full, so release it ...
+ wrapperToClose = wrapper;
+ }
+ } finally {
+ mainLock.unlock();
+ }
+ // Close the connection if we're supposed to (do it outside of the main lock)...
+ if (wrapperToClose != null) {
+ try {
+ closeConnection(wrapper);
+ } catch (InterruptedException e) {
+ // catch this, as there's not much we can do and the caller doesn't care or know how to handle it
+ this.logger.trace(e, "Interrupted while closing a repository connection");
+ }
+ }
+ }
+
+ /**
+ * Validate the supplied connection, returning the connection if valid or null if the connection is not valid.
+ *
+ * @param connection the connection to be validated; may not be null
+ * @return the validated connection, or null if the connection did not validate and was removed from the pool
+ */
+ protected ConnectionWrapper validateConnection( ConnectionWrapper connection ) {
+ assert connection != null;
+ ConnectionWrapper invalidConnection = null;
+ try {
+ if (!connection.ping(this.pingTimeout.get(), TimeUnit.NANOSECONDS)) {
+ invalidConnection = connection;
+ }
+ } catch (InterruptedException e) {
+ // catch this, as there's not much we can do and the caller doesn't care or know how to handle it
+ this.logger.trace(e, "Interrupted while pinging a repository connection");
+ invalidConnection = connection;
+ } finally {
+ if (invalidConnection != null) {
+ connection = null;
+ returnConnection(invalidConnection);
+ }
+ }
+ return connection;
+ }
+
+ /**
+ * Obtain a new connection wrapped in a {@link ConnectionWrapper}. This method does not check whether creating the new
+ * connection would violate the {@link #maximumPoolSize maximum pool size} nor does it add the new connection to the
+ * {@link #availableConnections available connections} (as the caller may want it immediately), but it does increment the
+ * {@link #poolSize pool size}.
+ *
+ * @return the connection wrapper with a new connection
+ * @throws RepositorySourceException if there was an error obtaining the new connection
+ * @throws InterruptedException if the thread was interrupted during the operation
+ */
+ @GuardedBy( "mainLock" )
+ protected ConnectionWrapper newWrappedConnection() throws RepositorySourceException, InterruptedException {
+ RepositoryConnection connection = this.connectionFactory.getConnection();
+ ++this.poolSize;
+ this.totalConnectionsCreated.incrementAndGet();
+ return new ConnectionWrapper(connection);
+ }
+
+ /**
+ * Close a connection that is in the pool but no longer in the {@link #availableConnections available connections}. This
+ * method does decrement the {@link #poolSize pool size}.
+ *
+ * @param wrapper the wrapper for the connection to be closed
+ * @throws InterruptedException if the thread was interrupted during the operation
+ */
+ protected void closeConnection( ConnectionWrapper wrapper ) throws InterruptedException {
+ assert wrapper != null;
+ RepositoryConnection original = wrapper.getOriginal();
+ assert original != null;
+ try {
+ this.logger.debug("Closing repository connection to {0}", getName());
+ original.close();
+ } finally {
+ final ReentrantLock mainLock = this.mainLock;
+ try {
+ mainLock.lock();
+ // No matter what reduce the pool size count
+ --this.poolSize;
+ // And if shutting down and this was the last connection being used...
+ if (this.runState == SHUTDOWN && this.poolSize <= 0) {
+ // then signal anybody that has called "awaitTermination(...)"
+ this.logger.trace("Signalling termination of repository connection pool for {0}", getName());
+ this.runState = TERMINATED;
+ this.termination.signalAll();
+ this.logger.trace("Terminated repository connection pool for {0}", getName());
+
+ // fall through to call terminate() outside of lock.
+ }
+ } finally {
+ mainLock.unlock();
+ }
+ }
+ }
+
+ @GuardedBy( "mainLock" )
+ protected int drainUnusedConnections( int count ) {
+ if (count <= 0) return 0;
+ this.logger.trace("Draining up to {0} unused repository connections to {1}", count, getName());
+ // Drain the extra connections from those available ...
+ Collection<ConnectionWrapper> extraConnections = new LinkedList<ConnectionWrapper>();
+ this.availableConnections.drainTo(extraConnections, count);
+ for (ConnectionWrapper connection : extraConnections) {
+ try {
+ this.logger.trace("Closing repository connection to {0}", getName());
+ connection.getOriginal().close();
+ } catch (InterruptedException e) {
+ // Ignore this ...
+ }
+ }
+ int numClosed = extraConnections.size();
+ this.poolSize -= numClosed;
+ this.logger.trace("Drained {0} unused connections", numClosed);
+ return numClosed;
+ }
+
+ @GuardedBy( "mainLock" )
+ protected boolean addConnectionIfUnderCorePoolSize() throws RepositorySourceException, InterruptedException {
+ // Add connection ...
+ if (this.poolSize < this.corePoolSize) {
+ this.availableConnections.offer(newWrappedConnection());
+ this.logger.trace("Added connection to {0} in undersized pool", getName());
+ return true;
+ }
+ return false;
+ }
+
+ @GuardedBy( "mainLock" )
+ protected int addConnectionsIfUnderCorePoolSize() throws RepositorySourceException, InterruptedException {
+ // Add connections ...
+ int n = 0;
+ while (this.poolSize < this.corePoolSize) {
+ this.availableConnections.offer(newWrappedConnection());
+ ++n;
+ }
+ this.logger.trace("Added {0} connection(s) to {1} in undersized pool", n, getName());
+ return n;
+ }
+
+ protected class ConnectionWrapper implements RepositoryConnection {
+
+ private final RepositoryConnection original;
+ private final long timeCreated;
+ private long lastUsed;
+ private boolean closed = false;
+
+ protected ConnectionWrapper( RepositoryConnection connection ) {
+ assert connection != null;
+ this.original = connection;
+ this.timeCreated = System.currentTimeMillis();
+ }
+
+ /**
+ * @return original
+ */
+ protected RepositoryConnection getOriginal() {
+ return this.original;
+ }
+
+ /**
+ * @return lastUsed
+ */
+ public long getTimeLastUsed() {
+ return this.lastUsed;
+ }
+
+ /**
+ * @return timeCreated
+ */
+ public long getTimeCreated() {
+ return this.timeCreated;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getSourceName() {
+ return this.original.getSourceName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public XAResource getXAResource() {
+ if (closed) throw new IllegalStateException(SpiI18n.closedConnectionMayNotBeUsed.text());
+ return this.original.getXAResource();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ if (closed) throw new IllegalStateException(SpiI18n.closedConnectionMayNotBeUsed.text());
+ return this.original.getDefaultCachePolicy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void execute( ExecutionEnvironment env,
+ GraphCommand... commands ) throws RepositorySourceException, InterruptedException {
+ if (closed) throw new IllegalStateException(SpiI18n.closedConnectionMayNotBeUsed.text());
+ this.original.execute(env, commands);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean ping( long time,
+ TimeUnit unit ) throws InterruptedException {
+ if (closed) throw new IllegalStateException(SpiI18n.closedConnectionMayNotBeUsed.text());
+ return this.original.ping(time, unit);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() throws InterruptedException {
+ if (!closed) {
+ this.lastUsed = System.currentTimeMillis();
+ this.original.close();
+ this.closed = true;
+ returnConnection(this);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setListener( RepositorySourceListener listener ) {
+ if (!closed) this.original.setListener(listener);
+ }
+
+ }
+
+}
Property changes on: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/BasicRepositoryConnectionPool.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Deleted: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPool.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -1,989 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.spi.graph.connection;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.Set;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.ReentrantLock;
-import javax.transaction.xa.XAResource;
-import net.jcip.annotations.GuardedBy;
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.dna.common.util.ArgCheck;
-import org.jboss.dna.common.util.Logger;
-import org.jboss.dna.spi.SpiI18n;
-import org.jboss.dna.spi.cache.CachePolicy;
-import org.jboss.dna.spi.graph.commands.GraphCommand;
-
-/**
- * @author Randall Hauch
- */
-@ThreadSafe
-public class RepositoryConnectionPool implements RepositoryConnectionFactory {
-
- /**
- * The core pool size for default-constructed pools is {@value}.
- */
- public static final int DEFAULT_CORE_POOL_SIZE = 1;
-
- /**
- * The maximum pool size for default-constructed pools is {@value}.
- */
- public static final int DEFAULT_MAXIMUM_POOL_SIZE = 10;
-
- /**
- * The keep-alive time for connections in default-constructed pools is {@value} seconds.
- */
- public static final long DEFAULT_KEEP_ALIVE_TIME_IN_SECONDS = 30;
-
- /**
- * Permission for checking shutdown
- */
- private static final RuntimePermission shutdownPerm = new RuntimePermission("modifyThread");
-
- /**
- * The factory that this pool uses to create new connections.
- */
- private final RepositoryConnectionFactory connectionFactory;
-
- /**
- * Lock held on updates to poolSize, corePoolSize, maximumPoolSize, and workers set.
- */
- private final ReentrantLock mainLock = new ReentrantLock();
-
- /**
- * Wait condition to support awaitTermination
- */
- private final Condition termination = mainLock.newCondition();
-
- /**
- * Set containing all connections that are available for use.
- */
- @GuardedBy( "mainLock" )
- private final BlockingQueue<ConnectionWrapper> availableConnections = new LinkedBlockingQueue<ConnectionWrapper>();
-
- /**
- * The connections that are currently in use.
- */
- @GuardedBy( "mainLock" )
- private final Set<ConnectionWrapper> inUseConnections = new HashSet<ConnectionWrapper>();
-
- /**
- * Timeout in nanoseconds for idle connections waiting to be used. Threads use this timeout only when there are more than
- * corePoolSize present. Otherwise they wait forever to be used.
- */
- private volatile long keepAliveTime;
-
- /**
- * The target pool size, updated only while holding mainLock, but volatile to allow concurrent readability even during
- * updates.
- */
- @GuardedBy( "mainLock" )
- private volatile int corePoolSize;
-
- /**
- * Maximum pool size, updated only while holding mainLock but volatile to allow concurrent readability even during updates.
- */
- @GuardedBy( "mainLock" )
- private volatile int maximumPoolSize;
-
- /**
- * Current pool size, updated only while holding mainLock but volatile to allow concurrent readability even during updates.
- */
- @GuardedBy( "mainLock" )
- private volatile int poolSize;
-
- /**
- * Lifecycle state, updated only while holding mainLock but volatile to allow concurrent readability even during updates.
- */
- @GuardedBy( "mainLock" )
- private volatile int runState;
-
- // Special values for runState
- /** Normal, not-shutdown mode */
- static final int RUNNING = 0;
- /** Controlled shutdown mode */
- static final int SHUTDOWN = 1;
- /** Immediate shutdown mode */
- static final int STOP = 2;
- /** Final state */
- static final int TERMINATED = 3;
-
- /**
- * Flag specifying whether a connection should be validated before returning it from the {@link #getConnection()} method.
- */
- private final AtomicBoolean validateConnectionBeforeUse = new AtomicBoolean(false);
-
- /**
- * The time in nanoseconds that ping should wait before timing out and failing.
- */
- private final AtomicLong pingTimeout = new AtomicLong(0);
-
- /**
- * The number of times an attempt to obtain a connection should fail with invalid connections before throwing an exception.
- */
- private final AtomicInteger maxFailedAttemptsBeforeError = new AtomicInteger(10);
-
- private final AtomicLong totalConnectionsCreated = new AtomicLong(0);
-
- private final AtomicLong totalConnectionsUsed = new AtomicLong(0);
-
- private final Logger logger = Logger.getLogger(this.getClass());
-
- /**
- * Create the pool to use the supplied connection factory, which is typically a {@link RepositorySource}. This constructor
- * uses the {@link #DEFAULT_CORE_POOL_SIZE default core pool size}, {@link #DEFAULT_MAXIMUM_POOL_SIZE default maximum pool
- * size}, and {@link #DEFAULT_KEEP_ALIVE_TIME_IN_SECONDS default keep-alive time (in seconds)}.
- *
- * @param connectionFactory the factory for connections
- * @throws IllegalArgumentException if the connection factory is null or any of the supplied arguments are invalid
- */
- public RepositoryConnectionPool( RepositoryConnectionFactory connectionFactory ) {
- this(connectionFactory, DEFAULT_CORE_POOL_SIZE, DEFAULT_MAXIMUM_POOL_SIZE, DEFAULT_KEEP_ALIVE_TIME_IN_SECONDS,
- TimeUnit.SECONDS);
- }
-
- /**
- * Create the pool to use the supplied connection factory, which is typically a {@link RepositorySource}.
- *
- * @param connectionFactory the factory for connections
- * @param corePoolSize the number of connections to keep in the pool, even if they are idle.
- * @param maximumPoolSize the maximum number of connections to allow in the pool.
- * @param keepAliveTime when the number of connection is greater than the core, this is the maximum time that excess idle
- * connections will be kept before terminating.
- * @param unit the time unit for the keepAliveTime argument.
- * @throws IllegalArgumentException if the connection factory is null or any of the supplied arguments are invalid
- */
- public RepositoryConnectionPool( RepositoryConnectionFactory connectionFactory,
- int corePoolSize,
- int maximumPoolSize,
- long keepAliveTime,
- TimeUnit unit ) {
- ArgCheck.isNonNegative(corePoolSize, "corePoolSize");
- ArgCheck.isPositive(maximumPoolSize, "maximumPoolSize");
- ArgCheck.isNonNegative(keepAliveTime, "keepAliveTime");
- ArgCheck.isNotNull(connectionFactory, "repository connection factory");
- if (maximumPoolSize < corePoolSize) {
- throw new IllegalArgumentException(SpiI18n.maximumPoolSizeMayNotBeSmallerThanCorePoolSize.text());
- }
- this.connectionFactory = connectionFactory;
- this.corePoolSize = corePoolSize;
- this.maximumPoolSize = maximumPoolSize;
- this.keepAliveTime = unit.toNanos(keepAliveTime);
- this.setPingTimeout(100, TimeUnit.MILLISECONDS);
- }
-
- public String getName() {
- return this.connectionFactory.getName();
- }
-
- // -------------------------------------------------
- // Property settings ...
- // -------------------------------------------------
-
- /**
- * @return validateConnectionBeforeUse
- */
- public boolean getValidateConnectionBeforeUse() {
- return this.validateConnectionBeforeUse.get();
- }
-
- /**
- * @param validateConnectionBeforeUse Sets validateConnectionBeforeUse to the specified value.
- */
- public void setValidateConnectionBeforeUse( boolean validateConnectionBeforeUse ) {
- this.validateConnectionBeforeUse.set(validateConnectionBeforeUse);
- }
-
- /**
- * @return pingTimeout
- */
- public long getPingTimeoutInNanos() {
- return this.pingTimeout.get();
- }
-
- /**
- * @param pingTimeout the time to wait for a ping to complete
- * @param unit the time unit of the time argument
- */
- public void setPingTimeout( long pingTimeout,
- TimeUnit unit ) {
- ArgCheck.isNonNegative(pingTimeout, "time");
- this.pingTimeout.set(unit.toNanos(pingTimeout));
- }
-
- /**
- * @return maxFailedAttemptsBeforeError
- */
- public int getMaxFailedAttemptsBeforeError() {
- return this.maxFailedAttemptsBeforeError.get();
- }
-
- /**
- * @param maxFailedAttemptsBeforeError Sets maxFailedAttemptsBeforeError to the specified value.
- */
- public void setMaxFailedAttemptsBeforeError( int maxFailedAttemptsBeforeError ) {
- this.maxFailedAttemptsBeforeError.set(maxFailedAttemptsBeforeError);
- }
-
- /**
- * Sets the time limit for which connections may remain idle before being closed. If there are more than the core number of
- * connections currently in the pool, after waiting this amount of time without being used, excess threads will be terminated.
- * This overrides any value set in the constructor.
- *
- * @param time the time to wait. A time value of zero will cause excess connections to terminate immediately after being
- * returned.
- * @param unit the time unit of the time argument
- * @throws IllegalArgumentException if time less than zero
- * @see #getKeepAliveTime
- */
- public void setKeepAliveTime( long time,
- TimeUnit unit ) {
- ArgCheck.isNonNegative(time, "time");
- this.keepAliveTime = unit.toNanos(time);
- }
-
- /**
- * Returns the connection keep-alive time, which is the amount of time which connections in excess of the core pool size may
- * remain idle before being closed.
- *
- * @param unit the desired time unit of the result
- * @return the time limit
- * @see #setKeepAliveTime
- */
- public long getKeepAliveTime( TimeUnit unit ) {
- assert unit != null;
- return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
- }
-
- /**
- * @return maximumPoolSize
- */
- public int getMaximumPoolSize() {
- return this.maximumPoolSize;
- }
-
- /**
- * Sets the maximum allowed number of connections. This overrides any value set in the constructor. If the new value is
- * smaller than the current value, excess existing but unused connections will be closed.
- *
- * @param maximumPoolSize the new maximum
- * @throws IllegalArgumentException if maximumPoolSize less than zero or the {@link #getCorePoolSize() core pool size}
- * @see #getMaximumPoolSize
- */
- public void setMaximumPoolSize( int maximumPoolSize ) {
- ArgCheck.isPositive(maximumPoolSize, "maximum pool size");
- if (maximumPoolSize < corePoolSize) {
- throw new IllegalArgumentException(SpiI18n.maximumPoolSizeMayNotBeSmallerThanCorePoolSize.text());
- }
- final ReentrantLock mainLock = this.mainLock;
- try {
- mainLock.lock();
- int extra = this.maximumPoolSize - maximumPoolSize;
- this.maximumPoolSize = maximumPoolSize;
- if (extra > 0 && poolSize > maximumPoolSize) {
- // Drain the extra connections from those available ...
- drainUnusedConnections(extra);
- }
- } finally {
- mainLock.unlock();
- }
- }
-
- /**
- * Returns the core number of connections.
- *
- * @return the core number of connections
- * @see #setCorePoolSize(int)
- */
- public int getCorePoolSize() {
- return this.corePoolSize;
- }
-
- /**
- * Sets the core number of connections. This overrides any value set in the constructor. If the new value is smaller than the
- * current value, excess existing and unused connections will be closed. If larger, new connections will, if needed, be
- * created.
- *
- * @param corePoolSize the new core size
- * @throws RepositorySourceException if there was an error obtaining the new connection
- * @throws InterruptedException if the thread was interrupted during the operation
- * @throws IllegalArgumentException if <tt>corePoolSize</tt> less than zero
- * @see #getCorePoolSize()
- */
- public void setCorePoolSize( int corePoolSize ) throws RepositorySourceException, InterruptedException {
- ArgCheck.isNonNegative(corePoolSize, "core pool size");
- if (maximumPoolSize < corePoolSize) {
- throw new IllegalArgumentException(SpiI18n.maximumPoolSizeMayNotBeSmallerThanCorePoolSize.text());
- }
- final ReentrantLock mainLock = this.mainLock;
- try {
- mainLock.lock();
- int extra = this.corePoolSize - corePoolSize;
- this.corePoolSize = corePoolSize;
- if (extra < 0) {
- // Add connections ...
- addConnectionsIfUnderCorePoolSize();
- } else if (extra > 0 && poolSize > corePoolSize) {
- // Drain the extra connections from those available ...
- drainUnusedConnections(extra);
- }
- } finally {
- mainLock.unlock();
- }
- }
-
- // -------------------------------------------------
- // Statistics ...
- // -------------------------------------------------
-
- /**
- * Returns the current number of connections in the pool, including those that are checked out (in use) and those that are not
- * being used.
- *
- * @return the number of connections
- */
- public int getPoolSize() {
- return poolSize;
- }
-
- /**
- * Returns the approximate number of connections that are currently checked out from the pool.
- *
- * @return the number of checked-out connections
- */
- public int getInUseCount() {
- final ReentrantLock mainLock = this.mainLock;
- try {
- mainLock.lock();
- return this.inUseConnections.size();
- } finally {
- mainLock.unlock();
- }
- }
-
- /**
- * Get the total number of connections that have been created by this pool.
- *
- * @return the total number of connections created by this pool
- */
- public long getTotalConnectionsCreated() {
- return this.totalConnectionsCreated.get();
- }
-
- /**
- * Get the total number of times connections have been {@link #getConnection()} used.
- *
- * @return the total number
- */
- public long getTotalConnectionsUsed() {
- return this.totalConnectionsUsed.get();
- }
-
- // -------------------------------------------------
- // State management methods ...
- // -------------------------------------------------
-
- /**
- * Starts a core connection, causing it to idly wait for use. This overrides the default policy of starting core connections
- * only when they are {@link #getConnection() needed}. This method will return <tt>false</tt> if all core connections have
- * already been started.
- *
- * @return true if a connection was started
- * @throws RepositorySourceException if there was an error obtaining the new connection
- * @throws InterruptedException if the thread was interrupted during the operation
- */
- public boolean prestartCoreConnection() throws RepositorySourceException, InterruptedException {
- final ReentrantLock mainLock = this.mainLock;
- try {
- mainLock.lock();
- return addConnectionIfUnderCorePoolSize();
- } finally {
- mainLock.unlock();
- }
- }
-
- /**
- * Starts all core connections, causing them to idly wait for use. This overrides the default policy of starting core
- * connections only when they are {@link #getConnection() needed}.
- *
- * @return the number of connections started.
- * @throws RepositorySourceException if there was an error obtaining the new connection
- * @throws InterruptedException if the thread was interrupted during the operation
- */
- public int prestartAllCoreConnections() throws RepositorySourceException, InterruptedException {
- final ReentrantLock mainLock = this.mainLock;
- try {
- mainLock.lock();
- return addConnectionsIfUnderCorePoolSize();
- } finally {
- mainLock.unlock();
- }
- }
-
- /**
- * Initiates an orderly shutdown in which connections that are currently in use are allowed to be used and closed as normal,
- * but no new connections will be created. Invocation has no additional effect if already shut down.
- *
- * @throws SecurityException if a security manager exists and shutting down this pool may manipulate threads that the caller
- * is not permitted to modify because it does not hold {@link java.lang.RuntimePermission}<tt>("modifyThread")</tt>,
- * or the security manager's <tt>checkAccess</tt> method denies access.
- * @see #shutdownNow()
- */
- public void shutdown() {
- // Fail if caller doesn't have modifyThread permission. We
- // explicitly check permissions directly because we can't trust
- // implementations of SecurityManager to correctly override
- // the "check access" methods such that our documented
- // security policy is implemented.
- SecurityManager security = System.getSecurityManager();
- if (security != null) java.security.AccessController.checkPermission(shutdownPerm);
-
- this.logger.debug("Shutting down repository connection pool for {0}", getName());
- boolean fullyTerminated = false;
- final ReentrantLock mainLock = this.mainLock;
- try {
- mainLock.lock();
- int state = this.runState;
- if (state == RUNNING) {
- // don't override shutdownNow
- this.runState = SHUTDOWN;
- }
-
- // Kill the maintenance thread ...
-
- // Remove and close all available connections ...
- if (!this.availableConnections.isEmpty()) {
- // Drain the extra connections from those available ...
- drainUnusedConnections(this.availableConnections.size());
- }
-
- // If there are no connections being used, trigger full termination now ...
- if (this.inUseConnections.isEmpty()) {
- fullyTerminated = true;
- this.logger.trace("Signalling termination of repository connection pool for {0}", getName());
- runState = TERMINATED;
- termination.signalAll();
- this.logger.debug("Terminated repository connection pool for {0}", getName());
- }
- // Otherwise the last connection that is closed will transition the runState to TERMINATED ...
- } finally {
- mainLock.unlock();
- }
- if (fullyTerminated) terminated();
- }
-
- /**
- * Attempts to close all connections, including those connections currently in use, and prevent the use of other connections.
- *
- * @throws SecurityException if a security manager exists and shutting down this pool may manipulate threads that the caller
- * is not permitted to modify because it does not hold {@link java.lang.RuntimePermission}<tt>("modifyThread")</tt>,
- * or the security manager's <tt>checkAccess</tt> method denies access.
- * @see #shutdown()
- */
- public void shutdownNow() {
- // Almost the same code as shutdown()
- SecurityManager security = System.getSecurityManager();
- if (security != null) java.security.AccessController.checkPermission(shutdownPerm);
-
- this.logger.debug("Shutting down (immediately) repository connection pool for {0}", getName());
- boolean fullyTerminated = false;
- final ReentrantLock mainLock = this.mainLock;
- try {
- mainLock.lock();
- int state = this.runState;
- if (state != TERMINATED) {
- // don't override shutdownNow
- this.runState = STOP;
- }
-
- // Kill the maintenance thread ...
-
- // Remove and close all available connections ...
- if (!this.availableConnections.isEmpty()) {
- // Drain the extra connections from those available ...
- drainUnusedConnections(this.availableConnections.size());
- }
-
- // If there are connections being used, close them now ...
- if (!this.inUseConnections.isEmpty()) {
- for (ConnectionWrapper connectionInUse : this.inUseConnections) {
- try {
- this.logger.trace("Closing repository connection to {0}", getName());
- connectionInUse.getOriginal().close();
- } catch (InterruptedException e) {
- // Ignore this ...
- }
- }
- this.poolSize -= this.inUseConnections.size();
- // The last connection that is closed will transition the runState to TERMINATED ...
- } else {
- // There are no connections in use, so trigger full termination now ...
- fullyTerminated = true;
- this.logger.trace("Signalling termination of repository connection pool for {0}", getName());
- runState = TERMINATED;
- termination.signalAll();
- this.logger.debug("Terminated repository connection pool for {0}", getName());
- }
-
- } finally {
- mainLock.unlock();
- }
- if (fullyTerminated) terminated();
- }
-
- /**
- * Return whether this connection pool is running and is able to {@link #getConnection() provide connections}. Note that this
- * method is effectively <code>!isShutdown()</code>.
- *
- * @return true if this pool is running, or false otherwise
- * @see #isShutdown()
- * @see #isTerminated()
- * @see #isTerminating()
- */
- public boolean isRunning() {
- return runState == RUNNING;
- }
-
- /**
- * Return whether this connection pool is in the process of shutting down or has already been shut down. A result of
- * <code>true</code> signals that the pool may no longer be used. Note that this method is effectively
- * <code>!isRunning()</code>.
- *
- * @return true if this pool has been shut down, or false otherwise
- * @see #isShutdown()
- * @see #isTerminated()
- * @see #isTerminating()
- */
- public boolean isShutdown() {
- return runState != RUNNING;
- }
-
- /**
- * Returns true if this pool is in the process of terminating after {@link #shutdown()} or {@link #shutdownNow()} has been
- * called but has not completely terminated. This method may be useful for debugging. A return of <tt>true</tt> reported a
- * sufficient period after shutdown may indicate that submitted tasks have ignored or suppressed interruption, causing this
- * executor not to properly terminate.
- *
- * @return true if terminating but not yet terminated, or false otherwise
- * @see #isTerminated()
- */
- public boolean isTerminating() {
- return runState == STOP;
- }
-
- /**
- * Return true if this pool has completed its termination and no longer has any open connections.
- *
- * @return true if terminated, or false otherwise
- * @see #isTerminating()
- */
- public boolean isTerminated() {
- return runState == TERMINATED;
- }
-
- /**
- * Method that can be called after {@link #shutdown()} or {@link #shutdownNow()} to wait until all connections in use at the
- * time those methods were called have been closed normally. This method accepts a maximum time duration, after which it will
- * return even if all connections have not been closed.
- *
- * @param timeout the maximum time to wait for all connections to be closed and returned to the pool
- * @param unit the time unit for <code>timeout</code>
- * @return true if the pool was terminated in the supplied time (or was already terminated), or false if the timeout occurred
- * before all the connections were closed
- * @throws InterruptedException if the thread was interrupted
- */
- public boolean awaitTermination( long timeout,
- TimeUnit unit ) throws InterruptedException {
- long nanos = unit.toNanos(timeout);
- final ReentrantLock mainLock = this.mainLock;
- try {
- mainLock.lock();
- for (;;) {
- // this.logger.debug("---> Run state = {}; condition = {}", runState, termination);
- if (runState == TERMINATED) return true;
- if (nanos <= 0) return false;
- nanos = termination.awaitNanos(nanos);
- // this.logger.debug("---> Done waiting: run state = {}; condition = {}", runState, termination);
- }
- } finally {
- mainLock.unlock();
- }
- }
-
- /**
- * Method invoked when the pool has terminated. Default implementation does nothing. Note: To properly nest multiple
- * overridings, subclasses should generally invoke <tt>super.terminated</tt> within this method.
- */
- protected void terminated() {
- }
-
- /**
- * Invokes <tt>shutdown</tt> when this pool is no longer referenced.
- */
- @Override
- protected void finalize() {
- shutdown();
- }
-
- // -------------------------------------------------
- // Connection management methods ...
- // -------------------------------------------------
-
- /**
- * {@inheritDoc}
- */
- public RepositoryConnection getConnection() throws RepositorySourceException, InterruptedException {
- int attemptsAllowed = this.maxFailedAttemptsBeforeError.get();
- ConnectionWrapper connection = null;
- // Do this until we get a good connection ...
- int attemptsRemaining = attemptsAllowed;
- while (connection == null && attemptsRemaining > 0) {
- --attemptsRemaining;
- ReentrantLock mainLock = this.mainLock;
- try {
- mainLock.lock();
- // If we're shutting down the pool, then just close the connection ...
- if (this.runState != RUNNING) {
- throw new IllegalStateException(SpiI18n.repositoryConnectionPoolIsNotRunning.text());
- }
- // If there are fewer total connections than the core size ...
- if (this.poolSize < this.corePoolSize) {
- // Immediately create a wrapped connection and return it ...
- connection = newWrappedConnection();
- }
- // Peek to see if there is a connection available ...
- else if (this.availableConnections.peek() != null) {
- // There is, so take it and return it ...
- connection = this.availableConnections.take();
- }
- // There is no connection available. If there are fewer total connections than the maximum size ...
- else if (this.poolSize < this.maximumPoolSize) {
- // Immediately create a wrapped connection and return it ...
- connection = newWrappedConnection();
- }
- if (connection != null) {
- this.inUseConnections.add(connection);
- }
- } finally {
- mainLock.unlock();
- }
- if (connection == null) {
- // There are not enough connections, so wait in line for the next available connection ...
- this.logger.trace("Waiting for a repository connection from pool {0}", getName());
- connection = this.availableConnections.take();
- mainLock = this.mainLock;
- mainLock.lock();
- try {
- if (connection != null) {
- this.inUseConnections.add(connection);
- }
- } finally {
- mainLock.unlock();
- }
- this.logger.trace("Recieved a repository connection from pool {0}", getName());
- }
- if (connection != null && this.validateConnectionBeforeUse.get()) {
- connection = validateConnection(connection);
- }
- }
- if (connection == null) {
- // We were unable to obtain a usable connection, so fail ...
- throw new RepositorySourceException(SpiI18n.unableToObtainValidRepositoryAfterAttempts.text(attemptsAllowed));
- }
- this.totalConnectionsUsed.incrementAndGet();
- return connection;
- }
-
- /**
- * This method is automatically called by the {@link ConnectionWrapper} when it is {@link ConnectionWrapper#close() closed}.
- *
- * @param wrapper the wrapper to the connection that is being returned to the pool
- */
- protected void returnConnection( ConnectionWrapper wrapper ) {
- assert wrapper != null;
- ConnectionWrapper wrapperToClose = null;
- final ReentrantLock mainLock = this.mainLock;
- try {
- mainLock.lock();
- // Remove the connection from the in-use set ...
- boolean removed = this.inUseConnections.remove(wrapper);
- assert removed;
-
- // If we're shutting down the pool, then just close the connection ...
- if (this.runState != RUNNING) {
- wrapperToClose = wrapper;
- }
- // If there are more connections than the maximum size...
- else if (this.poolSize > this.maximumPoolSize) {
- // Immediately close this connection ...
- wrapperToClose = wrapper;
- }
- // Attempt to make the connection available (this should generally work, unless there is an upper limit
- // to the number of available connections) ...
- else if (!this.availableConnections.offer(new ConnectionWrapper(wrapper.getOriginal()))) {
- // The pool of available connection is full, so release it ...
- wrapperToClose = wrapper;
- }
- } finally {
- mainLock.unlock();
- }
- // Close the connection if we're supposed to (do it outside of the main lock)...
- if (wrapperToClose != null) {
- try {
- closeConnection(wrapper);
- } catch (InterruptedException e) {
- // catch this, as there's not much we can do and the caller doesn't care or know how to handle it
- this.logger.trace(e, "Interrupted while closing a repository connection");
- }
- }
- }
-
- /**
- * Validate the supplied connection, returning the connection if valid or null if the connection is not valid.
- *
- * @param connection the connection to be validated; may not be null
- * @return the validated connection, or null if the connection did not validate and was removed from the pool
- */
- protected ConnectionWrapper validateConnection( ConnectionWrapper connection ) {
- assert connection != null;
- ConnectionWrapper invalidConnection = null;
- try {
- if (!connection.ping(this.pingTimeout.get(), TimeUnit.NANOSECONDS)) {
- invalidConnection = connection;
- }
- } catch (InterruptedException e) {
- // catch this, as there's not much we can do and the caller doesn't care or know how to handle it
- this.logger.trace(e, "Interrupted while pinging a repository connection");
- invalidConnection = connection;
- } finally {
- if (invalidConnection != null) {
- connection = null;
- returnConnection(invalidConnection);
- }
- }
- return connection;
- }
-
- /**
- * Obtain a new connection wrapped in a {@link ConnectionWrapper}. This method does not check whether creating the new
- * connection would violate the {@link #maximumPoolSize maximum pool size} nor does it add the new connection to the
- * {@link #availableConnections available connections} (as the caller may want it immediately), but it does increment the
- * {@link #poolSize pool size}.
- *
- * @return the connection wrapper with a new connection
- * @throws RepositorySourceException if there was an error obtaining the new connection
- * @throws InterruptedException if the thread was interrupted during the operation
- */
- @GuardedBy( "mainLock" )
- protected ConnectionWrapper newWrappedConnection() throws RepositorySourceException, InterruptedException {
- RepositoryConnection connection = this.connectionFactory.getConnection();
- ++this.poolSize;
- this.totalConnectionsCreated.incrementAndGet();
- return new ConnectionWrapper(connection);
- }
-
- /**
- * Close a connection that is in the pool but no longer in the {@link #availableConnections available connections}. This
- * method does decrement the {@link #poolSize pool size}.
- *
- * @param wrapper the wrapper for the connection to be closed
- * @throws InterruptedException if the thread was interrupted during the operation
- */
- protected void closeConnection( ConnectionWrapper wrapper ) throws InterruptedException {
- assert wrapper != null;
- RepositoryConnection original = wrapper.getOriginal();
- assert original != null;
- try {
- this.logger.debug("Closing repository connection to {0}", getName());
- original.close();
- } finally {
- final ReentrantLock mainLock = this.mainLock;
- try {
- mainLock.lock();
- // No matter what reduce the pool size count
- --this.poolSize;
- // And if shutting down and this was the last connection being used...
- if (this.runState == SHUTDOWN && this.poolSize <= 0) {
- // then signal anybody that has called "awaitTermination(...)"
- this.logger.trace("Signalling termination of repository connection pool for {0}", getName());
- this.runState = TERMINATED;
- this.termination.signalAll();
- this.logger.trace("Terminated repository connection pool for {0}", getName());
-
- // fall through to call terminate() outside of lock.
- }
- } finally {
- mainLock.unlock();
- }
- }
- }
-
- @GuardedBy( "mainLock" )
- protected int drainUnusedConnections( int count ) {
- if (count <= 0) return 0;
- this.logger.trace("Draining up to {0} unused repository connections to {1}", count, getName());
- // Drain the extra connections from those available ...
- Collection<ConnectionWrapper> extraConnections = new LinkedList<ConnectionWrapper>();
- this.availableConnections.drainTo(extraConnections, count);
- for (ConnectionWrapper connection : extraConnections) {
- try {
- this.logger.trace("Closing repository connection to {0}", getName());
- connection.getOriginal().close();
- } catch (InterruptedException e) {
- // Ignore this ...
- }
- }
- int numClosed = extraConnections.size();
- this.poolSize -= numClosed;
- this.logger.trace("Drained {0} unused connections", numClosed);
- return numClosed;
- }
-
- @GuardedBy( "mainLock" )
- protected boolean addConnectionIfUnderCorePoolSize() throws RepositorySourceException, InterruptedException {
- // Add connection ...
- if (this.poolSize < this.corePoolSize) {
- this.availableConnections.offer(newWrappedConnection());
- this.logger.trace("Added connection to {0} in undersized pool", getName());
- return true;
- }
- return false;
- }
-
- @GuardedBy( "mainLock" )
- protected int addConnectionsIfUnderCorePoolSize() throws RepositorySourceException, InterruptedException {
- // Add connections ...
- int n = 0;
- while (this.poolSize < this.corePoolSize) {
- this.availableConnections.offer(newWrappedConnection());
- ++n;
- }
- this.logger.trace("Added {0} connection(s) to {1} in undersized pool", n, getName());
- return n;
- }
-
- protected class ConnectionWrapper implements RepositoryConnection {
-
- private final RepositoryConnection original;
- private final long timeCreated;
- private long lastUsed;
- private boolean closed = false;
-
- protected ConnectionWrapper( RepositoryConnection connection ) {
- assert connection != null;
- this.original = connection;
- this.timeCreated = System.currentTimeMillis();
- }
-
- /**
- * @return original
- */
- protected RepositoryConnection getOriginal() {
- return this.original;
- }
-
- /**
- * @return lastUsed
- */
- public long getTimeLastUsed() {
- return this.lastUsed;
- }
-
- /**
- * @return timeCreated
- */
- public long getTimeCreated() {
- return this.timeCreated;
- }
-
- /**
- * {@inheritDoc}
- */
- public String getSourceName() {
- return this.original.getSourceName();
- }
-
- /**
- * {@inheritDoc}
- */
- public XAResource getXAResource() {
- if (closed) throw new IllegalStateException(SpiI18n.closedConnectionMayNotBeUsed.text());
- return this.original.getXAResource();
- }
-
- /**
- * {@inheritDoc}
- */
- public CachePolicy getDefaultCachePolicy() {
- if (closed) throw new IllegalStateException(SpiI18n.closedConnectionMayNotBeUsed.text());
- return this.original.getDefaultCachePolicy();
- }
-
- /**
- * {@inheritDoc}
- */
- public void execute( ExecutionEnvironment env,
- GraphCommand... commands ) throws RepositorySourceException, InterruptedException {
- if (closed) throw new IllegalStateException(SpiI18n.closedConnectionMayNotBeUsed.text());
- this.original.execute(env, commands);
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean ping( long time,
- TimeUnit unit ) throws InterruptedException {
- if (closed) throw new IllegalStateException(SpiI18n.closedConnectionMayNotBeUsed.text());
- return this.original.ping(time, unit);
- }
-
- /**
- * {@inheritDoc}
- */
- public void close() throws InterruptedException {
- if (!closed) {
- this.lastUsed = System.currentTimeMillis();
- this.original.close();
- this.closed = true;
- returnConnection(this);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public void setListener( RepositorySourceListener listener ) {
- if (!closed) this.original.setListener(listener);
- }
-
- }
-
-}
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperation.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperation.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperation.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -39,12 +39,14 @@
/**
* Run the operation using the supplied connection.
*
+ * @param env the environment in which this operation is executing; may not be null
* @param connection the connection; may not be null
* @return the result of the operation
* @throws RepositorySourceException if there is a problem with the connection
* @throws InterruptedException if this thread was interrupted
*/
- T run( RepositoryConnection connection ) throws RepositorySourceException, InterruptedException;
+ T run( ExecutionEnvironment env,
+ RepositoryConnection connection ) throws RepositorySourceException, InterruptedException;
/**
* A factory interface for creating repository operations.
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperations.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperations.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/connection/RepositoryOperations.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -37,17 +37,20 @@
* Call the supplied operation, using a connection from this pool.
*
* @param <T> the return type for the operation
+ * @param env the environment in which the operation is to execute; may not be null
* @param connectionFactory the factory for the connection to use
* @param operation the operation to be run using a new connection obtained from the factory
* @return the results from the operation
* @throws RepositorySourceException if there was an error obtaining the new connection
* @throws InterruptedException if the thread was interrupted during the operation
* @throws IllegalArgumentException if the operation is null
- * @see #createCallable(RepositoryConnectionFactory, RepositoryOperation)
- * @see #createCallables(RepositoryConnectionFactory, Iterable)
- * @see #createCallables(RepositoryConnectionFactory, RepositoryOperation...)
+ * @see #createCallable(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation)
+ * @see #createCallables(ExecutionEnvironment, RepositoryConnectionFactory, Iterable)
+ * @see #createCallables(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation...)
*/
- public static <T> T call( RepositoryConnectionFactory connectionFactory, RepositoryOperation<T> operation ) throws RepositorySourceException, InterruptedException {
+ public static <T> T call( ExecutionEnvironment env,
+ RepositoryConnectionFactory connectionFactory,
+ RepositoryOperation<T> operation ) throws RepositorySourceException, InterruptedException {
ArgCheck.isNotNull(operation, "repository operation");
// Get a connection ...
T result = null;
@@ -55,7 +58,7 @@
RepositoryConnection conn = connectionFactory.getConnection();
try {
// And run the client with the connection ...
- result = operation.run(conn);
+ result = operation.run(env, conn);
} finally {
conn.close();
}
@@ -68,14 +71,17 @@
* supplied factory.
*
* @param <T> the return type for the operation
+ * @param env the environment in which the operation is to execute; may not be null
* @param connectionFactory the factory for the connection to use
* @param operation the operation to be run using a new connection obtained from the factory
* @return the callable
- * @see #call(RepositoryConnectionFactory, RepositoryOperation)
- * @see #createCallables(RepositoryConnectionFactory, Iterable)
- * @see #createCallables(RepositoryConnectionFactory, RepositoryOperation...)
+ * @see #call(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation)
+ * @see #createCallables(ExecutionEnvironment, RepositoryConnectionFactory, Iterable)
+ * @see #createCallables(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation...)
*/
- public static <T> Callable<T> createCallable( final RepositoryConnectionFactory connectionFactory, final RepositoryOperation<T> operation ) {
+ public static <T> Callable<T> createCallable( final ExecutionEnvironment env,
+ final RepositoryConnectionFactory connectionFactory,
+ final RepositoryOperation<T> operation ) {
ArgCheck.isNotNull(operation, "repository operation");
return new Callable<T>() {
@@ -86,7 +92,7 @@
* @throws Exception
*/
public T call() throws Exception {
- return RepositoryOperations.call(connectionFactory, operation);
+ return RepositoryOperations.call(env, connectionFactory, operation);
}
};
}
@@ -96,17 +102,20 @@
* this pool.
*
* @param <T> the return type for the operations
+ * @param env the environment in which the operation is to execute; may not be null
* @param connectionFactory the factory for the connection to use
* @param operations the operations to be run using connections from the factory
* @return the collection of callables
- * @see #call(RepositoryConnectionFactory, RepositoryOperation)
- * @see #createCallable(RepositoryConnectionFactory, RepositoryOperation)
- * @see #createCallables(RepositoryConnectionFactory, Iterable)
+ * @see #call(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation)
+ * @see #createCallable(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation)
+ * @see #createCallables(ExecutionEnvironment, RepositoryConnectionFactory, Iterable)
*/
- public static <T> List<Callable<T>> createCallables( final RepositoryConnectionFactory connectionFactory, final RepositoryOperation<T>... operations ) {
+ public static <T> List<Callable<T>> createCallables( final ExecutionEnvironment env,
+ final RepositoryConnectionFactory connectionFactory,
+ final RepositoryOperation<T>... operations ) {
List<Callable<T>> callables = new ArrayList<Callable<T>>();
for (final RepositoryOperation<T> operation : operations) {
- callables.add(createCallable(connectionFactory, operation));
+ callables.add(createCallable(env, connectionFactory, operation));
}
return callables;
}
@@ -116,17 +125,20 @@
* this pool.
*
* @param <T> the return type for the operations
+ * @param env the environment in which the operation is to execute; may not be null
* @param connectionFactory the factory for the connection to use
* @param operations the operations to be run using connections from the factory
* @return the collection of callables
- * @see #call(RepositoryConnectionFactory, RepositoryOperation)
- * @see #createCallable(RepositoryConnectionFactory, RepositoryOperation)
- * @see #createCallables(RepositoryConnectionFactory, RepositoryOperation...)
+ * @see #call(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation)
+ * @see #createCallable(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation)
+ * @see #createCallables(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation...)
*/
- public static <T> List<Callable<T>> createCallables( final RepositoryConnectionFactory connectionFactory, Iterable<RepositoryOperation<T>> operations ) {
+ public static <T> List<Callable<T>> createCallables( final ExecutionEnvironment env,
+ final RepositoryConnectionFactory connectionFactory,
+ Iterable<RepositoryOperation<T>> operations ) {
List<Callable<T>> callables = new ArrayList<Callable<T>>();
for (final RepositoryOperation<T> operation : operations) {
- callables.add(createCallable(connectionFactory, operation));
+ callables.add(createCallable(env, connectionFactory, operation));
}
return callables;
}
@@ -136,18 +148,21 @@
* this pool.
*
* @param <T> the return type for the operations
+ * @param env the environment in which the operation is to execute; may not be null
* @param connectionFactory the factory for the connection to use
* @param operations the operations to be run using connections from the factory
* @return the collection of callables
- * @see #call(RepositoryConnectionFactory, RepositoryOperation)
- * @see #createCallable(RepositoryConnectionFactory, RepositoryOperation)
- * @see #createCallables(RepositoryConnectionFactory, RepositoryOperation...)
+ * @see #call(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation)
+ * @see #createCallable(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation)
+ * @see #createCallables(ExecutionEnvironment, RepositoryConnectionFactory, RepositoryOperation...)
*/
- public static <T> List<Callable<T>> createCallables( final RepositoryConnectionFactory connectionFactory, Iterator<RepositoryOperation<T>> operations ) {
+ public static <T> List<Callable<T>> createCallables( final ExecutionEnvironment env,
+ final RepositoryConnectionFactory connectionFactory,
+ Iterator<RepositoryOperation<T>> operations ) {
List<Callable<T>> callables = new ArrayList<Callable<T>>();
while (operations.hasNext()) {
final RepositoryOperation<T> operation = operations.next();
- callables.add(createCallable(connectionFactory, operation));
+ callables.add(createCallable(env, connectionFactory, operation));
}
return callables;
}
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/PathValueFactory.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/PathValueFactory.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/PathValueFactory.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -321,8 +321,30 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.PathFactory#create(org.jboss.dna.spi.graph.Path, org.jboss.dna.spi.graph.Path)
*/
public Path create( Path parentPath,
+ Path childPath ) {
+ ArgCheck.isNotNull(parentPath, "parent path");
+ ArgCheck.isNotNull(childPath, "child path");
+ if (childPath.size() == 0) return parentPath;
+ if (parentPath.size() == 0) {
+ // Just need to return the child path, but it must be absolute if the parent is ...
+ if (childPath.isAbsolute() == parentPath.isAbsolute()) return childPath;
+ // They aren't the same absoluteness, so create a new one ...
+ return new BasicPath(childPath.getSegmentsList(), parentPath.isAbsolute());
+ }
+ List<Segment> segments = new ArrayList<Segment>(parentPath.size() + childPath.size());
+ segments.addAll(parentPath.getSegmentsList());
+ segments.addAll(childPath.getSegmentsList());
+ return new BasicPath(segments, parentPath.isAbsolute());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Path create( Path parentPath,
Name segmentName,
int index ) {
ArgCheck.isNotNull(parentPath, "parent path");
Modified: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/StandardValueFactories.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/StandardValueFactories.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/impl/StandardValueFactories.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -23,9 +23,7 @@
import java.math.BigDecimal;
import java.net.URI;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.text.TextDecoder;
@@ -38,7 +36,6 @@
import org.jboss.dna.spi.graph.PathFactory;
import org.jboss.dna.spi.graph.PropertyType;
import org.jboss.dna.spi.graph.Reference;
-import org.jboss.dna.spi.graph.ValueFactories;
import org.jboss.dna.spi.graph.ValueFactory;
/**
@@ -47,7 +44,7 @@
* @author Randall Hauch
*/
@Immutable
-public class StandardValueFactories implements ValueFactories {
+public class StandardValueFactories extends AbstractValueFactories {
// This class is implemented with separate members for each factory so that the typical usage is optimized.
private final ValueFactory<String> stringFactory;
@@ -62,7 +59,6 @@
private final ValueFactory<Reference> referenceFactory;
private final ValueFactory<URI> uriFactory;
private final ValueFactory<Object> objectFactory;
- private final Map<PropertyType, ValueFactory<?>> factories;
private final NamespaceRegistry namespaceRegistry;
private final TextDecoder decoder;
@@ -85,10 +81,13 @@
* @param decoder the decoder that should be used; if null, the {@link ValueFactory#DEFAULT_DECODER default decoder} is used.
* @param encoder the encoder that should be used; if null, the {@link ValueFactory#DEFAULT_ENCODER default encoder} is used.
* @param extraFactories any extra factories that should be used; any factory will override the standard factories based upon
- * the {@link ValueFactory#getPropertyType() factory's property type}.
+ * the {@link ValueFactory#getPropertyType() factory's property type}.
* @throws IllegalArgumentException if the namespace registry is null
*/
- public StandardValueFactories( NamespaceRegistry namespaceRegistry, TextDecoder decoder, TextEncoder encoder, ValueFactory<?>... extraFactories ) {
+ public StandardValueFactories( NamespaceRegistry namespaceRegistry,
+ TextDecoder decoder,
+ TextEncoder encoder,
+ ValueFactory<?>... extraFactories ) {
ArgCheck.isNotNull(namespaceRegistry, "namespaceRegistry");
this.namespaceRegistry = namespaceRegistry;
this.decoder = decoder != null ? decoder : ValueFactory.DEFAULT_DECODER;
@@ -109,18 +108,18 @@
this.decimalFactory = getFactory(factories, new DecimalValueFactory(this.decoder, this.stringFactory));
this.doubleFactory = getFactory(factories, new DoubleValueFactory(this.decoder, this.stringFactory));
this.longFactory = getFactory(factories, new LongValueFactory(this.decoder, this.stringFactory));
- this.nameFactory = (NameFactory)getFactory(factories, new NameValueFactory(this.namespaceRegistry, this.decoder, this.stringFactory));
- this.pathFactory = (PathFactory)getFactory(factories, new PathValueFactory(this.decoder, this.stringFactory, this.nameFactory));
+ this.nameFactory = (NameFactory)getFactory(factories, new NameValueFactory(this.namespaceRegistry, this.decoder,
+ this.stringFactory));
+ this.pathFactory = (PathFactory)getFactory(factories, new PathValueFactory(this.decoder, this.stringFactory,
+ this.nameFactory));
this.referenceFactory = getFactory(factories, new UuidReferenceValueFactory(this.decoder, this.stringFactory));
this.uriFactory = getFactory(factories, new UriValueFactory(this.namespaceRegistry, this.decoder, this.stringFactory));
this.objectFactory = getFactory(factories, new ObjectValueFactory(this.decoder, this.stringFactory, this.binaryFactory));
-
- // Wrap the factories with an unmodifiable ...
- this.factories = Collections.unmodifiableMap(factories);
}
@SuppressWarnings( "unchecked" )
- private static <T> ValueFactory<T> getFactory( Map<PropertyType, ValueFactory<?>> factories, ValueFactory<T> defaultFactory ) {
+ private static <T> ValueFactory<T> getFactory( Map<PropertyType, ValueFactory<?>> factories,
+ ValueFactory<T> defaultFactory ) {
PropertyType type = defaultFactory.getPropertyType();
ValueFactory<?> factory = factories.get(type);
if (factory == null) {
@@ -145,13 +144,6 @@
}
/**
- * @return factories
- */
- public Map<PropertyType, ValueFactory<?>> getMapOfValueFactories() {
- return this.factories;
- }
-
- /**
* {@inheritDoc}
*/
public ValueFactory<Binary> getBinaryFactory() {
@@ -235,29 +227,4 @@
return this.objectFactory;
}
- /**
- * {@inheritDoc}
- */
- public Iterator<ValueFactory<?>> iterator() {
- return this.factories.values().iterator();
- }
-
- /**
- * {@inheritDoc}
- */
- public ValueFactory<?> getValueFactory( PropertyType type ) {
- ArgCheck.isNotNull(type, "type");
- return this.factories.get(type);
- }
-
- /**
- * {@inheritDoc}
- */
- public ValueFactory<?> getValueFactory( Object prototype ) {
- ArgCheck.isNotNull(prototype, "prototype");
- PropertyType inferredType = PropertyType.discoverType(prototype);
- assert inferredType != null;
- return this.factories.get(inferredType);
- }
-
}
Copied: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/BasicRepositoryConnectionPoolTest.java (from rev 307, trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPoolTest.java)
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/BasicRepositoryConnectionPoolTest.java (rev 0)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/BasicRepositoryConnectionPoolTest.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -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.spi.graph.connection;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.jboss.dna.spi.graph.connection.RepositorySourceLoadHarness.runLoadTest;
+import static org.junit.Assert.assertThat;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * @author Randall Hauch
+ */
+public class BasicRepositoryConnectionPoolTest {
+
+ private BasicRepositoryConnectionPool pool;
+ private TimeDelayingRepositorySource repositorySource;
+ private ExecutionEnvironment env;
+
+ @Before
+ public void beforeEach() {
+ this.repositorySource = new TimeDelayingRepositorySource("source 1");
+ this.pool = new BasicRepositoryConnectionPool(this.repositorySource, 1, 1, 100, TimeUnit.SECONDS);
+ this.env = null;
+ }
+
+ @After
+ public void afterEach() throws Exception {
+ pool.shutdown();
+ pool.awaitTermination(2, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void shouldBeCreatedInRunningState() {
+ assertThat(pool.isShutdown(), is(false));
+ assertThat(pool.isTerminating(), is(false));
+ assertThat(pool.isTerminated(), is(false));
+ assertThat(pool.getTotalConnectionsCreated(), is(0l));
+ assertThat(pool.getTotalConnectionsUsed(), is(0l));
+ }
+
+ @Test
+ public void shouldShutdownWhenNoConnectionsWereCreatedOrUsed() throws InterruptedException {
+ assertThat(pool.isShutdown(), is(false));
+ assertThat(pool.isTerminating(), is(false));
+ assertThat(pool.isTerminated(), is(false));
+ assertThat(pool.getTotalConnectionsCreated(), is(0l));
+ assertThat(pool.getTotalConnectionsUsed(), is(0l));
+
+ for (int i = 0; i != 4; ++i) {
+ pool.shutdown();
+ assertThat(pool.isShutdown() || pool.isTerminating() || pool.isTerminated(), is(true));
+ pool.awaitTermination(2, TimeUnit.SECONDS);
+ assertThat(pool.isTerminated(), is(true));
+ assertThat(pool.getTotalConnectionsCreated(), is(0l));
+ assertThat(pool.getTotalConnectionsUsed(), is(0l));
+ }
+ }
+
+ @Test
+ public void shouldCreateConnectionAndRecoverWhenClosed() throws RepositorySourceException, InterruptedException {
+ assertThat(pool.getTotalConnectionsCreated(), is(0l));
+ assertThat(pool.getTotalConnectionsUsed(), is(0l));
+
+ RepositoryConnection conn = pool.getConnection();
+ assertThat(conn, is(notNullValue()));
+ assertThat(pool.getTotalConnectionsCreated(), is(1l));
+ assertThat(pool.getTotalConnectionsUsed(), is(1l));
+ assertThat(pool.getPoolSize(), is(1));
+
+ conn.close();
+
+ assertThat(pool.getTotalConnectionsCreated(), is(1l));
+ assertThat(pool.getTotalConnectionsUsed(), is(1l));
+ assertThat(pool.getPoolSize(), is(1));
+ }
+
+ @Test
+ public void shouldAllowShutdownToBeCalledMultipleTimesEvenWhenShutdown()
+ throws RepositorySourceException, InterruptedException {
+ assertThat(pool.getTotalConnectionsCreated(), is(0l));
+ assertThat(pool.getTotalConnectionsUsed(), is(0l));
+
+ RepositoryConnection conn = pool.getConnection();
+ assertThat(conn, is(notNullValue()));
+ assertThat(pool.getTotalConnectionsCreated(), is(1l));
+ assertThat(pool.getTotalConnectionsUsed(), is(1l));
+ assertThat(pool.getPoolSize(), is(1));
+
+ conn.close();
+
+ assertThat(pool.getTotalConnectionsCreated(), is(1l));
+ assertThat(pool.getTotalConnectionsUsed(), is(1l));
+ assertThat(pool.getPoolSize(), is(1));
+
+ pool.shutdown();
+ pool.shutdown();
+ pool.awaitTermination(2, TimeUnit.SECONDS);
+ assertThat(pool.isTerminated(), is(true));
+ assertThat(pool.getTotalConnectionsCreated(), is(1l));
+ assertThat(pool.getTotalConnectionsUsed(), is(1l));
+ pool.shutdown();
+ pool.awaitTermination(2, TimeUnit.SECONDS);
+ pool.shutdown();
+ pool.awaitTermination(2, TimeUnit.SECONDS);
+ }
+
+ @Test( expected = IllegalStateException.class )
+ public void shouldNotCreateConnectionIfPoolIsNotRunning() throws RepositorySourceException, InterruptedException {
+ pool.shutdown();
+ pool.awaitTermination(2, TimeUnit.SECONDS);
+ assertThat(pool.isTerminated(), is(true));
+ assertThat(pool.getTotalConnectionsCreated(), is(0l));
+ assertThat(pool.getTotalConnectionsUsed(), is(0l));
+ pool.getConnection(); // this should fail with illegal state
+ }
+
+ @Test
+ public void shouldAllowConnectionsToBeClosedMoreThanOnceWithNoIllEffects()
+ throws RepositorySourceException, InterruptedException {
+ assertThat(pool.getTotalConnectionsCreated(), is(0l));
+ assertThat(pool.getTotalConnectionsUsed(), is(0l));
+
+ RepositoryConnection conn = pool.getConnection();
+ assertThat(conn, is(notNullValue()));
+ assertThat(pool.getTotalConnectionsCreated(), is(1l));
+ assertThat(pool.getTotalConnectionsUsed(), is(1l));
+ assertThat(pool.getPoolSize(), is(1));
+
+ conn.close();
+ conn.close();
+ }
+
+ @Test
+ public void shouldBlockClientsWhenNotEnoughConnections() throws Exception {
+ int numConnectionsInPool = 1;
+ int numClients = 2;
+ BasicRepositoryConnectionPool pool = new BasicRepositoryConnectionPool(repositorySource);
+ pool.setCorePoolSize(numConnectionsInPool);
+ pool.setMaximumPoolSize(numConnectionsInPool);
+ RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(10);
+ runLoadTest(env, pool, numClients, 100, TimeUnit.MILLISECONDS, operationFactory);
+ pool.shutdown();
+ pool.awaitTermination(4, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void shouldLimitClientsToRunSequentiallyWithOneConnectionInPool() throws Exception {
+ int numConnectionsInPool = 1;
+ int numClients = 3;
+ BasicRepositoryConnectionPool pool = new BasicRepositoryConnectionPool(repositorySource);
+ pool.setCorePoolSize(numConnectionsInPool);
+ pool.setMaximumPoolSize(numConnectionsInPool);
+ RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(10);
+ runLoadTest(env, pool, numClients, 100, TimeUnit.MILLISECONDS, operationFactory);
+ pool.shutdown();
+ pool.awaitTermination(4, TimeUnit.SECONDS);
+ }
+
+ @Test
+ public void shouldClientsToRunConncurrentlyWithTwoConnectionsInPool() throws Exception {
+ int numConnectionsInPool = 2;
+ int numClients = 10;
+ BasicRepositoryConnectionPool pool = new BasicRepositoryConnectionPool(repositorySource);
+ pool.setCorePoolSize(numConnectionsInPool);
+ pool.setMaximumPoolSize(numConnectionsInPool);
+ RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(10);
+ runLoadTest(env, pool, numClients, 100, TimeUnit.MILLISECONDS, operationFactory);
+ pool.shutdown();
+ pool.awaitTermination(4, TimeUnit.SECONDS);
+ }
+
+ @Ignore( "doesn't run on hudson" )
+ @Test
+ public void shouldClientsToRunConncurrentlyWithMultipleConnectionInPool() throws Exception {
+ int numConnectionsInPool = 10;
+ int numClients = 50;
+ BasicRepositoryConnectionPool pool = new BasicRepositoryConnectionPool(repositorySource);
+ pool.setCorePoolSize(numConnectionsInPool);
+ pool.setMaximumPoolSize(numConnectionsInPool);
+ RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(20);
+ List<Future<Integer>> results = runLoadTest(env, pool, numClients, 200, TimeUnit.MILLISECONDS, operationFactory);
+ int total = 0;
+ for (Future<Integer> result : results) {
+ assertThat(result.isDone(), is(true));
+ if (result.isDone()) total += result.get();
+ }
+ assertThat(total, is(20 * numClients));
+ pool.shutdown();
+ pool.awaitTermination(4, TimeUnit.SECONDS);
+ }
+
+}
Property changes on: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/BasicRepositoryConnectionPoolTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Deleted: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPoolTest.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPoolTest.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositoryConnectionPoolTest.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -1,222 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.spi.graph.connection;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNull.notNullValue;
-import static org.jboss.dna.spi.graph.connection.RepositorySourceLoadHarness.runLoadTest;
-import static org.junit.Assert.assertThat;
-import java.util.List;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-/**
- * @author Randall Hauch
- */
-public class RepositoryConnectionPoolTest {
-
- private RepositoryConnectionPool pool;
- private TimeDelayingRepositorySource repositorySource;
- private ExecutionEnvironment env;
-
- @Before
- public void beforeEach() {
- this.repositorySource = new TimeDelayingRepositorySource("source 1");
- this.pool = new RepositoryConnectionPool(this.repositorySource, 1, 1, 100, TimeUnit.SECONDS);
- this.env = null;
- }
-
- @After
- public void afterEach() throws Exception {
- pool.shutdown();
- pool.awaitTermination(2, TimeUnit.SECONDS);
- }
-
- @Test
- public void shouldBeCreatedInRunningState() {
- assertThat(pool.isShutdown(), is(false));
- assertThat(pool.isTerminating(), is(false));
- assertThat(pool.isTerminated(), is(false));
- assertThat(pool.getTotalConnectionsCreated(), is(0l));
- assertThat(pool.getTotalConnectionsUsed(), is(0l));
- }
-
- @Test
- public void shouldShutdownWhenNoConnectionsWereCreatedOrUsed() throws InterruptedException {
- assertThat(pool.isShutdown(), is(false));
- assertThat(pool.isTerminating(), is(false));
- assertThat(pool.isTerminated(), is(false));
- assertThat(pool.getTotalConnectionsCreated(), is(0l));
- assertThat(pool.getTotalConnectionsUsed(), is(0l));
-
- for (int i = 0; i != 4; ++i) {
- pool.shutdown();
- assertThat(pool.isShutdown() || pool.isTerminating() || pool.isTerminated(), is(true));
- pool.awaitTermination(2, TimeUnit.SECONDS);
- assertThat(pool.isTerminated(), is(true));
- assertThat(pool.getTotalConnectionsCreated(), is(0l));
- assertThat(pool.getTotalConnectionsUsed(), is(0l));
- }
- }
-
- @Test
- public void shouldCreateConnectionAndRecoverWhenClosed() throws RepositorySourceException, InterruptedException {
- assertThat(pool.getTotalConnectionsCreated(), is(0l));
- assertThat(pool.getTotalConnectionsUsed(), is(0l));
-
- RepositoryConnection conn = pool.getConnection();
- assertThat(conn, is(notNullValue()));
- assertThat(pool.getTotalConnectionsCreated(), is(1l));
- assertThat(pool.getTotalConnectionsUsed(), is(1l));
- assertThat(pool.getPoolSize(), is(1));
-
- conn.close();
-
- assertThat(pool.getTotalConnectionsCreated(), is(1l));
- assertThat(pool.getTotalConnectionsUsed(), is(1l));
- assertThat(pool.getPoolSize(), is(1));
- }
-
- @Test
- public void shouldAllowShutdownToBeCalledMultipleTimesEvenWhenShutdown()
- throws RepositorySourceException, InterruptedException {
- assertThat(pool.getTotalConnectionsCreated(), is(0l));
- assertThat(pool.getTotalConnectionsUsed(), is(0l));
-
- RepositoryConnection conn = pool.getConnection();
- assertThat(conn, is(notNullValue()));
- assertThat(pool.getTotalConnectionsCreated(), is(1l));
- assertThat(pool.getTotalConnectionsUsed(), is(1l));
- assertThat(pool.getPoolSize(), is(1));
-
- conn.close();
-
- assertThat(pool.getTotalConnectionsCreated(), is(1l));
- assertThat(pool.getTotalConnectionsUsed(), is(1l));
- assertThat(pool.getPoolSize(), is(1));
-
- pool.shutdown();
- pool.shutdown();
- pool.awaitTermination(2, TimeUnit.SECONDS);
- assertThat(pool.isTerminated(), is(true));
- assertThat(pool.getTotalConnectionsCreated(), is(1l));
- assertThat(pool.getTotalConnectionsUsed(), is(1l));
- pool.shutdown();
- pool.awaitTermination(2, TimeUnit.SECONDS);
- pool.shutdown();
- pool.awaitTermination(2, TimeUnit.SECONDS);
- }
-
- @Test( expected = IllegalStateException.class )
- public void shouldNotCreateConnectionIfPoolIsNotRunning() throws RepositorySourceException, InterruptedException {
- pool.shutdown();
- pool.awaitTermination(2, TimeUnit.SECONDS);
- assertThat(pool.isTerminated(), is(true));
- assertThat(pool.getTotalConnectionsCreated(), is(0l));
- assertThat(pool.getTotalConnectionsUsed(), is(0l));
- pool.getConnection(); // this should fail with illegal state
- }
-
- @Test
- public void shouldAllowConnectionsToBeClosedMoreThanOnceWithNoIllEffects()
- throws RepositorySourceException, InterruptedException {
- assertThat(pool.getTotalConnectionsCreated(), is(0l));
- assertThat(pool.getTotalConnectionsUsed(), is(0l));
-
- RepositoryConnection conn = pool.getConnection();
- assertThat(conn, is(notNullValue()));
- assertThat(pool.getTotalConnectionsCreated(), is(1l));
- assertThat(pool.getTotalConnectionsUsed(), is(1l));
- assertThat(pool.getPoolSize(), is(1));
-
- conn.close();
- conn.close();
- }
-
- @Test
- public void shouldBlockClientsWhenNotEnoughConnections() throws Exception {
- int numConnectionsInPool = 1;
- int numClients = 2;
- RepositoryConnectionPool pool = new RepositoryConnectionPool(repositorySource);
- pool.setCorePoolSize(numConnectionsInPool);
- pool.setMaximumPoolSize(numConnectionsInPool);
- RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(env,
- 10);
- runLoadTest(pool, numClients, 100, TimeUnit.MILLISECONDS, operationFactory);
- pool.shutdown();
- pool.awaitTermination(4, TimeUnit.SECONDS);
- }
-
- @Test
- public void shouldLimitClientsToRunSequentiallyWithOneConnectionInPool() throws Exception {
- int numConnectionsInPool = 1;
- int numClients = 3;
- RepositoryConnectionPool pool = new RepositoryConnectionPool(repositorySource);
- pool.setCorePoolSize(numConnectionsInPool);
- pool.setMaximumPoolSize(numConnectionsInPool);
- RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(env,
- 10);
- runLoadTest(pool, numClients, 100, TimeUnit.MILLISECONDS, operationFactory);
- pool.shutdown();
- pool.awaitTermination(4, TimeUnit.SECONDS);
- }
-
- @Test
- public void shouldClientsToRunConncurrentlyWithTwoConnectionsInPool() throws Exception {
- int numConnectionsInPool = 2;
- int numClients = 10;
- RepositoryConnectionPool pool = new RepositoryConnectionPool(repositorySource);
- pool.setCorePoolSize(numConnectionsInPool);
- pool.setMaximumPoolSize(numConnectionsInPool);
- RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(env,
- 10);
- runLoadTest(pool, numClients, 100, TimeUnit.MILLISECONDS, operationFactory);
- pool.shutdown();
- pool.awaitTermination(4, TimeUnit.SECONDS);
- }
-
- @Ignore( "doesn't run on hudson" )
- @Test
- public void shouldClientsToRunConncurrentlyWithMultipleConnectionInPool() throws Exception {
- int numConnectionsInPool = 10;
- int numClients = 50;
- RepositoryConnectionPool pool = new RepositoryConnectionPool(repositorySource);
- pool.setCorePoolSize(numConnectionsInPool);
- pool.setMaximumPoolSize(numConnectionsInPool);
- RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(env,
- 20);
- List<Future<Integer>> results = runLoadTest(pool, numClients, 200, TimeUnit.MILLISECONDS, operationFactory);
- int total = 0;
- for (Future<Integer> result : results) {
- assertThat(result.isDone(), is(true));
- if (result.isDone()) total += result.get();
- }
- assertThat(total, is(20 * numClients));
- pool.shutdown();
- pool.awaitTermination(4, TimeUnit.SECONDS);
- }
-
-}
Modified: trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositorySourceLoadHarness.java
===================================================================
--- trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositorySourceLoadHarness.java 2008-06-30 21:34:41 UTC (rev 319)
+++ trunk/dna-spi/src/test/java/org/jboss/dna/spi/graph/connection/RepositorySourceLoadHarness.java 2008-06-30 21:42:54 UTC (rev 320)
@@ -41,16 +41,23 @@
*/
public class RepositorySourceLoadHarness {
- public static Future<Integer> execute( RepositoryConnectionFactory connectionFactory, ExecutionEnvironment env, long maxTime, TimeUnit maxTimeUnit ) throws InterruptedException {
+ public static Future<Integer> execute( RepositoryConnectionFactory connectionFactory,
+ ExecutionEnvironment env,
+ long maxTime,
+ TimeUnit maxTimeUnit ) throws InterruptedException {
int numTimes = 1;
int numClients = 1;
- RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(env, numTimes);
- List<Future<Integer>> results = runLoadTest(connectionFactory, numClients, maxTime, maxTimeUnit, operationFactory);
+ RepositoryOperation.Factory<Integer> operationFactory = RepositorySourceLoadHarness.createMultipleLoadOperationFactory(numTimes);
+ List<Future<Integer>> results = runLoadTest(env, connectionFactory, numClients, maxTime, maxTimeUnit, operationFactory);
return results.get(0);
}
- public static <T> List<Future<T>> runLoadTest( RepositoryConnectionFactory connectionFactory, int numClients, long maxTime, TimeUnit maxTimeUnit, RepositoryOperation.Factory<T> clientFactory )
- throws InterruptedException {
+ public static <T> List<Future<T>> runLoadTest( ExecutionEnvironment env,
+ RepositoryConnectionFactory connectionFactory,
+ int numClients,
+ long maxTime,
+ TimeUnit maxTimeUnit,
+ RepositoryOperation.Factory<T> clientFactory ) throws InterruptedException {
// Create the clients ...
Collection<RepositoryOperation<T>> clients = new ArrayList<RepositoryOperation<T>>();
for (int i = 0; i != numClients; ++i) {
@@ -58,21 +65,28 @@
}
// and run the test ...
- return runLoadTest(connectionFactory, maxTime, maxTimeUnit, clients);
+ return runLoadTest(env, connectionFactory, maxTime, maxTimeUnit, clients);
}
- public static <T> List<Future<T>> runLoadTest( RepositoryConnectionFactory connectionFactory, long maxTime, TimeUnit maxTimeUnit, RepositoryOperation<T>... clients ) throws InterruptedException {
+ public static <T> List<Future<T>> runLoadTest( ExecutionEnvironment env,
+ RepositoryConnectionFactory connectionFactory,
+ long maxTime,
+ TimeUnit maxTimeUnit,
+ RepositoryOperation<T>... clients ) throws InterruptedException {
// Create the client collection ...
Collection<RepositoryOperation<T>> clientCollection = new ArrayList<RepositoryOperation<T>>();
for (RepositoryOperation<T> client : clients) {
if (client != null) clientCollection.add(client);
}
// and run the test ...
- return runLoadTest(connectionFactory, maxTime, maxTimeUnit, clientCollection);
+ return runLoadTest(env, connectionFactory, maxTime, maxTimeUnit, clientCollection);
}
- public static <T> List<Future<T>> runLoadTest( RepositoryConnectionFactory connectionFactory, long maxTime, TimeUnit maxTimeUnit, Collection<RepositoryOperation<T>> clients )
- throws InterruptedException {
+ public static <T> List<Future<T>> runLoadTest( ExecutionEnvironment env,
+ RepositoryConnectionFactory connectionFactory,
+ long maxTime,
+ TimeUnit maxTimeUnit,
+ Collection<RepositoryOperation<T>> clients ) throws InterruptedException {
assert connectionFactory != null;
assert clients != null;
assert clients.size() > 0;
@@ -88,7 +102,7 @@
try {
// Wrap each client by a callable and by another that uses a latch ...
- List<Callable<T>> callables = RepositoryOperations.createCallables(connectionFactory, clients);
+ List<Callable<T>> callables = RepositoryOperations.createCallables(env, connectionFactory, clients);
// Run the tests ...
List<Future<T>> futures = clientPool.invokeAll(callables, maxTime, maxTimeUnit);
@@ -153,15 +167,14 @@
* {@link RepositoryConnection#execute(ExecutionEnvironment, org.jboss.dna.spi.graph.commands.GraphCommand...)} the supplied
* number of times, intermixed with random math operations and {@link Thread#yield() yielding}.
*
- * @param env the environment
* @param callsPerOperation the number of <code>load</code> calls per RepositoryOperation
* @return the factory
*/
- public static RepositoryOperation.Factory<Integer> createMultipleLoadOperationFactory( final ExecutionEnvironment env, final int callsPerOperation ) {
+ public static RepositoryOperation.Factory<Integer> createMultipleLoadOperationFactory( final int callsPerOperation ) {
return new RepositoryOperation.Factory<Integer>() {
public RepositoryOperation<Integer> create() {
- return new CallLoadMultipleTimes(env, callsPerOperation);
+ return new CallLoadMultipleTimes(callsPerOperation);
}
};
}
@@ -169,12 +182,10 @@
public static class CallLoadMultipleTimes implements RepositoryOperation<Integer> {
private final int count;
- private final ExecutionEnvironment env;
- public CallLoadMultipleTimes( ExecutionEnvironment env, int count ) {
+ public CallLoadMultipleTimes( int count ) {
Logger.getLogger(RepositorySourceLoadHarness.class).debug("Creating repository operation to call {0} times", count);
this.count = count;
- this.env = env;
}
/**
@@ -186,8 +197,12 @@
/**
* {@inheritDoc}
+ *
+ * @see org.jboss.dna.spi.graph.connection.RepositoryOperation#run(org.jboss.dna.spi.graph.connection.ExecutionEnvironment,
+ * org.jboss.dna.spi.graph.connection.RepositoryConnection)
*/
- public Integer run( RepositoryConnection connection ) throws RepositorySourceException, InterruptedException {
+ public Integer run( ExecutionEnvironment env,
+ RepositoryConnection connection ) throws RepositorySourceException, InterruptedException {
Logger.getLogger(RepositorySourceLoadHarness.class).debug("Running {0} operation", this.getClass().getSimpleName());
int total = count;
for (int i = 0; i != count; ++i) {
15 years, 9 months
DNA SVN: r319 - in trunk/connectors/dna-connector-jbosscache/src/main: resources/org/jboss/dna/connector/jbosscache and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-06-30 17:34:41 -0400 (Mon, 30 Jun 2008)
New Revision: 319
Modified:
trunk/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java
trunk/connectors/dna-connector-jbosscache/src/main/resources/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.properties
Log:
Added support for composite command
Modified: trunk/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java
===================================================================
--- trunk/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java 2008-06-30 21:33:07 UTC (rev 318)
+++ trunk/connectors/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java 2008-06-30 21:34:41 UTC (rev 319)
@@ -36,6 +36,7 @@
import org.jboss.dna.spi.graph.Property;
import org.jboss.dna.spi.graph.Path.Segment;
import org.jboss.dna.spi.graph.commands.ActsOnPath;
+import org.jboss.dna.spi.graph.commands.CompositeCommand;
import org.jboss.dna.spi.graph.commands.CopyBranchCommand;
import org.jboss.dna.spi.graph.commands.CopyNodeCommand;
import org.jboss.dna.spi.graph.commands.CreateNodeCommand;
@@ -140,121 +141,137 @@
// Now execute the commands ...
for (GraphCommand command : commands) {
- // This node reference is available for any command that extends ActsOnPath ...
- Node<Name, Object> node = null;
+ executeCommand(env, command);
+ }
+ }
- // First, process the commands that create a new node ...
- if (command instanceof CreateNodeCommand) {
- CreateNodeCommand theCommand = (CreateNodeCommand)command;
- Path path = theCommand.getPath();
- Path parent = path.getAncestor();
- Fqn<Segment> childFqn = getFullyQualifiedName(path.getLastSegment());
- // Look up the parent node, which must exist ...
- Node<Name, Object> parentNode = getNode(env, parent);
- node = parentNode.addChild(childFqn);
- // Add the UUID property (if required), which may be overwritten by a supplied property ...
- Name uuidPropertyName = getUuidProperty(env);
- if (uuidPropertyName != null) {
- node.put(uuidPropertyName, generateUuid());
- }
- // Now add the properties to the supplied node ...
- for (Property property : theCommand.getProperties()) {
- if (property.size() == 0) continue;
- Name propName = property.getName();
- Object value = null;
- if (property.size() == 1) {
- value = property.iterator().next();
- } else {
- value = property.getValuesAsArray();
- }
- node.put(propName, value);
- }
- assert node != null;
+ /**
+ * @param env
+ * @param command
+ */
+ protected void executeCommand( ExecutionEnvironment env,
+ GraphCommand command ) {
+ // This node reference is available for any command that extends ActsOnPath ...
+ Node<Name, Object> node = null;
+
+ if (command instanceof CompositeCommand) {
+ CompositeCommand theCommand = (CompositeCommand)command;
+ for (GraphCommand containedCommand : theCommand) {
+ executeCommand(env, containedCommand);
}
+ }
- // Otherwise, check whether the command is applies to a path; all the remaining commands
- // that do so expect the node to exist ...
- else if (command instanceof ActsOnPath) {
- ActsOnPath theCommand = (ActsOnPath)command;
- Path path = theCommand.getPath();
- // Look up the node with the supplied path ...
- node = getNode(env, path);
- assert node != null;
+ // First, process the commands that create a new node ...
+ if (command instanceof CreateNodeCommand) {
+ CreateNodeCommand theCommand = (CreateNodeCommand)command;
+ Path path = theCommand.getPath();
+ Path parent = path.getAncestor();
+ Fqn<Segment> childFqn = getFullyQualifiedName(path.getLastSegment());
+ // Look up the parent node, which must exist ...
+ Node<Name, Object> parentNode = getNode(env, parent);
+ node = parentNode.addChild(childFqn);
+ // Add the UUID property (if required), which may be overwritten by a supplied property ...
+ Name uuidPropertyName = getUuidProperty(env);
+ if (uuidPropertyName != null) {
+ node.put(uuidPropertyName, generateUuid());
}
-
- if (command instanceof GetChildrenCommand) {
- GetChildrenCommand theCommand = (GetChildrenCommand)command;
- assert command instanceof ActsOnPath;
- assert node != null;
- // Get the names of the children ...
- List<Segment> childSegments = new ArrayList<Segment>();
- for (Node<Name, Object> child : node.getChildren()) {
- childSegments.add((Segment)child.getFqn().getLastElement());
+ // Now add the properties to the supplied node ...
+ for (Property property : theCommand.getProperties()) {
+ if (property.size() == 0) continue;
+ Name propName = property.getName();
+ Object value = null;
+ if (property.size() == 1) {
+ value = property.iterator().next();
+ } else {
+ value = property.getValuesAsArray();
}
- theCommand.setChildren(childSegments);
+ node.put(propName, value);
+ }
+ assert node != null;
+ }
+ // Otherwise, check whether the command is applies to a path; all the remaining commands
+ // that do so expect the node to exist ...
+ else if (command instanceof ActsOnPath) {
+ ActsOnPath theCommand = (ActsOnPath)command;
+ Path path = theCommand.getPath();
+ // Look up the node with the supplied path ...
+ node = getNode(env, path);
+ assert node != null;
+ }
+
+ if (command instanceof GetChildrenCommand) {
+ GetChildrenCommand theCommand = (GetChildrenCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ // Get the names of the children ...
+ List<Segment> childSegments = new ArrayList<Segment>();
+ for (Node<Name, Object> child : node.getChildren()) {
+ childSegments.add((Segment)child.getFqn().getLastElement());
}
- if (command instanceof GetPropertiesCommand) {
- GetPropertiesCommand theCommand = (GetPropertiesCommand)command;
- assert command instanceof ActsOnPath;
- assert node != null;
- Map<Name, Object> dataMap = node.getData();
- for (Map.Entry<Name, Object> data : dataMap.entrySet()) {
- Name propertyName = data.getKey();
- Object values = data.getValue();
- Property property = env.getPropertyFactory().create(propertyName, values);
- theCommand.setProperty(property);
- }
+ theCommand.setChildren(childSegments);
+
+ }
+ if (command instanceof GetPropertiesCommand) {
+ GetPropertiesCommand theCommand = (GetPropertiesCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ Map<Name, Object> dataMap = node.getData();
+ for (Map.Entry<Name, Object> data : dataMap.entrySet()) {
+ Name propertyName = data.getKey();
+ Object values = data.getValue();
+ Property property = env.getPropertyFactory().create(propertyName, values);
+ theCommand.setProperty(property);
}
- if (command instanceof SetPropertiesCommand) {
- SetPropertiesCommand theCommand = (SetPropertiesCommand)command;
- assert command instanceof ActsOnPath;
- assert node != null;
- // Now set (or remove) the properties to the supplied node ...
- for (Property property : theCommand.getProperties()) {
- Name propName = property.getName();
- if (property.size() == 0) {
- node.remove(propName);
- continue;
- }
- Object value = null;
- if (property.size() == 1) {
- value = property.iterator().next();
- } else {
- value = property.getValuesAsArray();
- }
- node.put(propName, value);
+ }
+ if (command instanceof SetPropertiesCommand) {
+ SetPropertiesCommand theCommand = (SetPropertiesCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ // Now set (or remove) the properties to the supplied node ...
+ for (Property property : theCommand.getProperties()) {
+ Name propName = property.getName();
+ if (property.size() == 0) {
+ node.remove(propName);
+ continue;
}
+ Object value = null;
+ if (property.size() == 1) {
+ value = property.iterator().next();
+ } else {
+ value = property.getValuesAsArray();
+ }
+ node.put(propName, value);
}
- if (command instanceof DeleteBranchCommand) {
- assert command instanceof ActsOnPath;
- assert node != null;
- node.getParent().removeChild(node.getFqn().getLastElement());
- }
- if (command instanceof CopyNodeCommand) {
- CopyNodeCommand theCommand = (CopyNodeCommand)command;
- boolean recursive = command instanceof CopyBranchCommand;
- // Look up the new parent, which must exist ...
- Path newPath = theCommand.getNewPath();
- Node<Name, Object> newParent = getNode(env, newPath.getAncestor());
- copyNode(node, newParent, recursive, null);
- }
- if (command instanceof MoveBranchCommand) {
- MoveBranchCommand theCommand = (MoveBranchCommand)command;
- assert command instanceof ActsOnPath;
- assert node != null;
- boolean recursive = true;
- Name uuidProperty = getUuidProperty(env);
- // Look up the new parent, which must exist ...
- Path newPath = theCommand.getNewPath();
- Node<Name, Object> newParent = getNode(env, newPath.getAncestor());
- copyNode(node, newParent, recursive, uuidProperty);
- // Now delete the old node ...
- Node<Name, Object> oldParent = node.getParent();
- boolean removed = oldParent.removeChild(node.getFqn().getLastElement());
- assert removed;
- }
}
+ if (command instanceof DeleteBranchCommand) {
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ node.getParent().removeChild(node.getFqn().getLastElement());
+ }
+ if (command instanceof CopyNodeCommand) {
+ CopyNodeCommand theCommand = (CopyNodeCommand)command;
+ boolean recursive = command instanceof CopyBranchCommand;
+ // Look up the new parent, which must exist ...
+ Path newPath = theCommand.getNewPath();
+ Node<Name, Object> newParent = getNode(env, newPath.getAncestor());
+ copyNode(node, newParent, recursive, null);
+ }
+ if (command instanceof MoveBranchCommand) {
+ MoveBranchCommand theCommand = (MoveBranchCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ boolean recursive = true;
+ Name uuidProperty = getUuidProperty(env);
+ // Look up the new parent, which must exist ...
+ Path newPath = theCommand.getNewPath();
+ Node<Name, Object> newParent = getNode(env, newPath.getAncestor());
+ copyNode(node, newParent, recursive, uuidProperty);
+ // Now delete the old node ...
+ Node<Name, Object> oldParent = node.getParent();
+ boolean removed = oldParent.removeChild(node.getFqn().getLastElement());
+ assert removed;
+ }
}
/**
Modified: trunk/connectors/dna-connector-jbosscache/src/main/resources/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.properties
===================================================================
--- trunk/connectors/dna-connector-jbosscache/src/main/resources/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.properties 2008-06-30 21:33:07 UTC (rev 318)
+++ trunk/connectors/dna-connector-jbosscache/src/main/resources/org/jboss/dna/connector/jbosscache/JBossCacheConnectorI18n.properties 2008-06-30 21:34:41 UTC (rev 319)
@@ -20,5 +20,5 @@
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
#
-connectorName = In-Memory Connector
+connectorName = JBoss Cache Connector
nodeDoesNotExist = Could not find an existing node at {0}
\ No newline at end of file
15 years, 9 months
DNA SVN: r318 - trunk.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-06-30 17:33:07 -0400 (Mon, 30 Jun 2008)
New Revision: 318
Modified:
trunk/pom.xml
Log:
DNA-167 Simple in-memory connector: Added connector project to parent POM
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2008-06-30 21:32:40 UTC (rev 317)
+++ trunk/pom.xml 2008-06-30 21:33:07 UTC (rev 318)
@@ -104,6 +104,7 @@
<module>sequencers/dna-sequencer-cnd</module>
<module>sequencers/dna-sequencer-java</module>
<module>sequencers/dna-sequencer-msoffice</module>
+ <module>connectors/dna-connector-inmemory</module>
<module>connectors/dna-connector-jbosscache</module>
<module>dna-integration-tests</module>
</modules>
15 years, 9 months
DNA SVN: r317 - in trunk/connectors: dna-connector-inmemory and 21 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-06-30 17:32:40 -0400 (Mon, 30 Jun 2008)
New Revision: 317
Added:
trunk/connectors/dna-connector-inmemory/
trunk/connectors/dna-connector-inmemory/.classpath
trunk/connectors/dna-connector-inmemory/.project
trunk/connectors/dna-connector-inmemory/pom.xml
trunk/connectors/dna-connector-inmemory/src/
trunk/connectors/dna-connector-inmemory/src/main/
trunk/connectors/dna-connector-inmemory/src/main/java/
trunk/connectors/dna-connector-inmemory/src/main/java/org/
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.java
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositorySource.java
trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/Node.java
trunk/connectors/dna-connector-inmemory/src/main/resources/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/inmemory/
trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.properties
trunk/connectors/dna-connector-inmemory/src/test/
trunk/connectors/dna-connector-inmemory/src/test/java/
trunk/connectors/dna-connector-inmemory/src/test/java/org/
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/inmemory/
trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryTest.java
trunk/connectors/dna-connector-inmemory/src/test/resources/
Log:
DNA-167 Simple in-memory connector: Created a simple in-memory repository and connector
Property changes on: trunk/connectors/dna-connector-inmemory
___________________________________________________________________
Name: svn:ignore
+ target
Added: trunk/connectors/dna-connector-inmemory/.classpath
===================================================================
--- trunk/connectors/dna-connector-inmemory/.classpath (rev 0)
+++ trunk/connectors/dna-connector-inmemory/.classpath 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
Added: trunk/connectors/dna-connector-inmemory/.project
===================================================================
--- trunk/connectors/dna-connector-inmemory/.project (rev 0)
+++ trunk/connectors/dna-connector-inmemory/.project 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>dna-connector-inmemory</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.maven.ide.eclipse.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.maven.ide.eclipse.maven2Nature</nature>
+ </natures>
+</projectDescription>
Added: trunk/connectors/dna-connector-inmemory/pom.xml
===================================================================
--- trunk/connectors/dna-connector-inmemory/pom.xml (rev 0)
+++ trunk/connectors/dna-connector-inmemory/pom.xml 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna</artifactId>
+ <version>0.2-SNAPSHOT</version>
+ <relativePath>../..</relativePath>
+ </parent>
+ <!-- The groupId and version values are inherited from parent -->
+ <artifactId>dna-connector-inmemory</artifactId>
+ <packaging>jar</packaging>
+ <name>JBoss DNA Connector to a simple in-memory repository</name>
+ <description>JBoss DNA Connector that accesses an in-memory graph.</description>
+ <url>http://labs.jboss.org/dna</url>
+
+ <properties>
+ <dna-version>0.2-SNAPSHOT</dna-version>
+ </properties>
+ <!--
+ Define the dependencies. Note that all version and scopes default to those
+ defined in the dependencyManagement section of the parent pom.
+ -->
+ <dependencies>
+ <!--
+ Common
+ -->
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>${dna-version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-spi</artifactId>
+ <version>${dna-version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <!--
+ Testing (note the scope)
+ -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ </dependency>
+ <!--
+ Logging (require SLF4J API for compiling, but use Log4J and its SLF4J binding for testing)
+ -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <!--
+ Java Concurrency in Practice annotations
+ -->
+ <dependency>
+ <groupId>net.jcip</groupId>
+ <artifactId>jcip-annotations</artifactId>
+ </dependency>
+ </dependencies>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
\ No newline at end of file
Added: trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.java
===================================================================
--- trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.java (rev 0)
+++ trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.java 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,55 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.inmemory;
+
+import java.util.Locale;
+import java.util.Set;
+import org.jboss.dna.common.i18n.I18n;
+
+/**
+ * @author Randall Hauch
+ */
+public final class InMemoryConnectorI18n {
+
+ public static I18n connectorName;
+ public static I18n nodeDoesNotExist;
+
+ static {
+ try {
+ I18n.initialize(InMemoryConnectorI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ public static Set<Locale> getLocalizationProblemLocales() {
+ return I18n.getLocalizationProblemLocales(InMemoryConnectorI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems() {
+ return I18n.getLocalizationProblems(InMemoryConnectorI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems( Locale locale ) {
+ return I18n.getLocalizationProblems(InMemoryConnectorI18n.class, locale);
+ }
+}
Added: trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java
===================================================================
--- trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java (rev 0)
+++ trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,266 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.inmemory;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+
+/**
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public class InMemoryRepository {
+
+ protected final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private final String name;
+ private final UUID rootNodeUuid;
+ private final Map<UUID, Node> nodesByUuid = new HashMap<UUID, Node>();
+
+ public InMemoryRepository( String name,
+ UUID rootNodeUUID ) {
+ ArgCheck.isNotNull(rootNodeUUID, "rootNodeUUID");
+ ArgCheck.isNotEmpty(name, "name");
+ this.name = name;
+ this.rootNodeUuid = rootNodeUUID;
+ // Create the root node ...
+ Node root = new Node(rootNodeUUID);
+ nodesByUuid.put(root.getUuid(), root);
+ }
+
+ /**
+ * @return lock
+ */
+ public ReadWriteLock getLock() {
+ return lock;
+ }
+
+ /**
+ * @return name
+ */
+ public String getName() {
+ return name;
+ }
+
+ public Node getRoot() {
+ return nodesByUuid.get(this.rootNodeUuid);
+ }
+
+ public Node getNode( UUID uuid ) {
+ assert uuid != null;
+ return nodesByUuid.get(uuid);
+ }
+
+ protected Map<UUID, Node> getNodesByUuid() {
+ return nodesByUuid;
+ }
+
+ public Node getNode( ExecutionEnvironment env,
+ String path ) {
+ assert env != null;
+ assert path != null;
+ return getNode(env.getValueFactories().getPathFactory().create(path));
+ }
+
+ /**
+ * Find a node with the given path.
+ *
+ * @param path the path to the node; may not be null
+ * @return the node with the path, or null if the node does not exist
+ */
+ public Node getNode( Path path ) {
+ assert path != null;
+ Node node = getRoot();
+ for (Path.Segment segment : path) {
+ Node desiredChild = null;
+ for (Node child : node.getChildren()) {
+ if (child == null) continue;
+ Path.Segment childName = child.getName();
+ if (childName == null) continue;
+ if (childName.equals(segment)) {
+ desiredChild = child;
+ break;
+ }
+ }
+ if (desiredChild != null) {
+ node = desiredChild;
+ } else {
+ return null;
+ }
+ }
+ return node;
+ }
+
+ protected UUID generateUuid() {
+ return UUID.randomUUID();
+ }
+
+ public void removeNode( ExecutionEnvironment env,
+ Node node ) {
+ assert env != null;
+ assert node != null;
+ assert getRoot().equals(node) != true;
+ Node parent = node.getParent();
+ assert parent != null;
+ parent.getChildren().remove(node);
+ correctSameNameSiblingIndexes(env, parent, node.getName().getName());
+ removeUuidReference(node);
+ }
+
+ protected void removeUuidReference( Node node ) {
+ nodesByUuid.remove(node.getUuid());
+ for (Node child : node.getChildren()) {
+ removeUuidReference(child);
+ }
+ }
+
+ /**
+ * Create a node at the supplied path. The parent of the new node must already exist.
+ *
+ * @param env the environment; may not be null
+ * @param pathToNewNode the path to the new node; may not be null
+ * @return the new node (or root if the path specified the root)
+ */
+ public Node createNode( ExecutionEnvironment env,
+ String pathToNewNode ) {
+ assert env != null;
+ assert pathToNewNode != null;
+ Path path = env.getValueFactories().getPathFactory().create(pathToNewNode);
+ if (path.isRoot()) return getRoot();
+ Path parentPath = path.getAncestor();
+ Node parentNode = getNode(parentPath);
+ Name name = path.getLastSegment().getName();
+ return createNode(env, parentNode, name);
+ }
+
+ /**
+ * Create a new node with the supplied name, as a child of the supplied parent.
+ *
+ * @param env the execution environment
+ * @param parentNode the parent node; may not be null
+ * @param name the name; may not be null
+ * @return the new node
+ */
+ public Node createNode( ExecutionEnvironment env,
+ Node parentNode,
+ Name name ) {
+ assert env != null;
+ assert name != null;
+ if (parentNode == null) parentNode = getRoot();
+ Node node = new Node(generateUuid());
+ nodesByUuid.put(node.getUuid(), node);
+ node.setParent(parentNode);
+ Path.Segment newName = env.getValueFactories().getPathFactory().createSegment(name);
+ node.setName(newName);
+ parentNode.getChildren().add(node);
+ correctSameNameSiblingIndexes(env, parentNode, name);
+ return node;
+ }
+
+ protected void correctSameNameSiblingIndexes( ExecutionEnvironment env,
+ Node parentNode,
+ Name name ) {
+ if (parentNode == null) return;
+ // Look for the highest existing index ...
+ List<Node> childrenWithSameNames = new LinkedList<Node>();
+ for (Node child : parentNode.getChildren()) {
+ if (child.getName().getName().equals(name)) childrenWithSameNames.add(child);
+ }
+ if (childrenWithSameNames.size() == 0) return;
+ if (childrenWithSameNames.size() == 1) {
+ Node childWithSameName = childrenWithSameNames.get(0);
+ Path.Segment newName = env.getValueFactories().getPathFactory().createSegment(name, Path.NO_INDEX);
+ childWithSameName.setName(newName);
+ return;
+ }
+ int index = 1;
+ for (Node childWithSameName : childrenWithSameNames) {
+ Path.Segment segment = childWithSameName.getName();
+ if (segment.getIndex() != index) {
+ Path.Segment newName = env.getValueFactories().getPathFactory().createSegment(name, index);
+ childWithSameName.setName(newName);
+ }
+ ++index;
+ }
+ }
+
+ /**
+ * Move the supplied node to the new parent. This method automatically removes the node from its existing parent, and also
+ * correctly adjusts the {@link Path.Segment#getIndex() index} to be correct in the new parent.
+ *
+ * @param env
+ * @param node the node to be moved; may not be the {@link #getRoot() root}
+ * @param newParent the new parent; may not be the {@link #getRoot() root}
+ */
+ public void moveNode( ExecutionEnvironment env,
+ Node node,
+ Node newParent ) {
+ assert env != null;
+ assert newParent != null;
+ assert node != null;
+ assert getRoot().equals(newParent) != true;
+ assert getRoot().equals(node) != true;
+ Node oldParent = node.getParent();
+ if (oldParent != null) {
+ if (oldParent.equals(newParent)) return;
+ boolean removed = oldParent.getChildren().remove(node);
+ assert removed == true;
+ node.setParent(null);
+ correctSameNameSiblingIndexes(env, oldParent, node.getName().getName());
+ }
+ node.setParent(newParent);
+ newParent.getChildren().add(node);
+ correctSameNameSiblingIndexes(env, newParent, node.getName().getName());
+ }
+
+ public int copyNode( ExecutionEnvironment env,
+ Node original,
+ Node newParent,
+ boolean recursive ) {
+ assert env != null;
+ assert original != null;
+ assert newParent != null;
+ // Get or create the new node ...
+ Node copy = createNode(env, newParent, original.getName().getName());
+
+ // Copy the properties ...
+ copy.getProperties().clear();
+ copy.getProperties().putAll(original.getProperties());
+ int numNodesCopied = 1;
+ if (recursive) {
+ // Loop over each child and call this method ...
+ for (Node child : original.getChildren()) {
+ numNodesCopied += copyNode(env, child, copy, true);
+ }
+ }
+ return numNodesCopied;
+ }
+}
Added: trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java
===================================================================
--- trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java (rev 0)
+++ trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,267 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.inmemory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import javax.transaction.xa.XAResource;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.InvalidPathException;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.Path.Segment;
+import org.jboss.dna.spi.graph.commands.ActsAsUpdate;
+import org.jboss.dna.spi.graph.commands.ActsOnPath;
+import org.jboss.dna.spi.graph.commands.CompositeCommand;
+import org.jboss.dna.spi.graph.commands.CopyBranchCommand;
+import org.jboss.dna.spi.graph.commands.CopyNodeCommand;
+import org.jboss.dna.spi.graph.commands.CreateNodeCommand;
+import org.jboss.dna.spi.graph.commands.DeleteBranchCommand;
+import org.jboss.dna.spi.graph.commands.GetChildrenCommand;
+import org.jboss.dna.spi.graph.commands.GetPropertiesCommand;
+import org.jboss.dna.spi.graph.commands.GraphCommand;
+import org.jboss.dna.spi.graph.commands.MoveBranchCommand;
+import org.jboss.dna.spi.graph.commands.SetPropertiesCommand;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositorySourceListener;
+
+/**
+ * @author Randall Hauch
+ */
+public class InMemoryRepositoryConnection implements RepositoryConnection {
+
+ protected static final RepositorySourceListener NO_OP_LISTENER = new RepositorySourceListener() {
+
+ /**
+ * {@inheritDoc}
+ */
+ public void notify( String sourceName,
+ Object... events ) {
+ // do nothing
+ }
+ };
+
+ private final InMemoryRepositorySource source;
+ private final InMemoryRepository content;
+ private RepositorySourceListener listener = NO_OP_LISTENER;
+
+ InMemoryRepositoryConnection( InMemoryRepositorySource source,
+ InMemoryRepository content ) {
+ assert source != null;
+ assert content != null;
+ this.source = source;
+ this.content = content;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getSourceName() {
+ return source.getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ return source.getDefaultCachePolicy();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public XAResource getXAResource() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean ping( long time,
+ TimeUnit unit ) {
+ this.content.getRoot();
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setListener( RepositorySourceListener listener ) {
+ this.listener = listener != null ? listener : NO_OP_LISTENER;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void execute( ExecutionEnvironment env,
+ GraphCommand... commands ) {
+ // Do any commands update/write?
+ Lock lock = this.content.getLock().readLock();
+ for (GraphCommand command : commands) {
+ if (command instanceof ActsAsUpdate) {
+ lock = this.content.getLock().writeLock();
+ break;
+ }
+ }
+
+ try {
+ // Obtain the lock ...
+ lock.lock();
+ // Now execute the commands ...
+ for (GraphCommand command : commands) {
+ executeCommand(env, command);
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @param env
+ * @param command
+ */
+ protected void executeCommand( ExecutionEnvironment env,
+ GraphCommand command ) {
+ // This node reference is available for any command that extends ActsOnPath ...
+ Node node = null;
+
+ if (command instanceof CompositeCommand) {
+ CompositeCommand theCommand = (CompositeCommand)command;
+ for (GraphCommand containedCommand : theCommand) {
+ executeCommand(env, containedCommand);
+ }
+ }
+
+ // First, process the commands that create a new node ...
+ if (command instanceof CreateNodeCommand) {
+ CreateNodeCommand theCommand = (CreateNodeCommand)command;
+ Path path = theCommand.getPath();
+ Path parent = path.getAncestor();
+ // Look up the parent node, which must exist ...
+ Node parentNode = content.getNode(parent);
+ node = content.createNode(env, parentNode, path.getLastSegment().getName());
+ // Now add the properties to the supplied node ...
+ for (Property property : theCommand.getProperties()) {
+ Name propName = property.getName();
+ if (property.size() == 0) {
+ node.getProperties().remove(propName);
+ continue;
+ }
+ node.getProperties().put(propName, property);
+ }
+ assert node != null;
+ }
+
+ // Otherwise, check whether the command is applies to a path; all the remaining commands
+ // that do so expect the node to exist ...
+ else if (command instanceof ActsOnPath) {
+ ActsOnPath theCommand = (ActsOnPath)command;
+ Path path = theCommand.getPath();
+ // Look up the node with the supplied path ...
+ node = content.getNode(path);
+ if (node == null) throw new InvalidPathException(InMemoryConnectorI18n.nodeDoesNotExist.text(path));
+ }
+
+ if (command instanceof GetChildrenCommand) {
+ GetChildrenCommand theCommand = (GetChildrenCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ // Get the names of the children ...
+ List<Node> children = node.getChildren();
+ List<Segment> childSegments = new ArrayList<Segment>(children.size());
+ for (Node child : children) {
+ childSegments.add(child.getName());
+ }
+ theCommand.setChildren(childSegments);
+
+ }
+ if (command instanceof GetPropertiesCommand) {
+ GetPropertiesCommand theCommand = (GetPropertiesCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ for (Property property : node.getProperties().values()) {
+ theCommand.setProperty(property);
+ }
+ }
+ if (command instanceof SetPropertiesCommand) {
+ SetPropertiesCommand theCommand = (SetPropertiesCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ // Now set (or remove) the properties to the supplied node ...
+ for (Property property : theCommand.getProperties()) {
+ Name propName = property.getName();
+ if (property.size() == 0) {
+ node.getProperties().remove(propName);
+ continue;
+ }
+ node.getProperties().put(propName, property);
+ }
+ }
+ if (command instanceof DeleteBranchCommand) {
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ content.removeNode(env, node);
+ }
+ if (command instanceof CopyNodeCommand) {
+ CopyNodeCommand theCommand = (CopyNodeCommand)command;
+ boolean recursive = command instanceof CopyBranchCommand;
+ // Look up the new parent, which must exist ...
+ Path newPath = theCommand.getNewPath();
+ Node newParent = content.getNode(newPath.getAncestor());
+ if (newParent == null) {
+ throw new InvalidPathException(InMemoryConnectorI18n.nodeDoesNotExist.text(newPath.getAncestor()));
+ }
+ content.copyNode(env, node, newParent, recursive);
+ }
+ if (command instanceof MoveBranchCommand) {
+ MoveBranchCommand theCommand = (MoveBranchCommand)command;
+ assert command instanceof ActsOnPath;
+ assert node != null;
+ // Look up the new parent, which must exist ...
+ Path newPath = theCommand.getNewPath();
+ Node newParent = content.getNode(newPath.getAncestor());
+ if (newParent == null) {
+ throw new InvalidPathException(InMemoryConnectorI18n.nodeDoesNotExist.text(newPath.getAncestor()));
+ }
+ node.setParent(newParent);
+ }
+ }
+
+ /**
+ * @return listener
+ */
+ protected RepositorySourceListener getListener() {
+ return this.listener;
+ }
+
+}
Added: trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositorySource.java
===================================================================
--- trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositorySource.java (rev 0)
+++ trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositorySource.java 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,277 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.inmemory;
+
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.ObjectFactory;
+import net.jcip.annotations.GuardedBy;
+import org.jboss.dna.common.util.ArgCheck;
+import org.jboss.dna.spi.cache.CachePolicy;
+import org.jboss.dna.spi.graph.connection.RepositoryConnection;
+import org.jboss.dna.spi.graph.connection.RepositorySource;
+
+/**
+ * @author Randall Hauch
+ */
+public class InMemoryRepositorySource implements RepositorySource, ObjectFactory {
+
+ /**
+ * The initial version is 1
+ */
+ private static final long serialVersionUID = 1L;
+
+ public static final String DEFAULT_UUID_PROPERTY_NAMESPACE = "http://www.jboss.org/dna/connector/jbosscache";
+ public static final String DEFAULT_UUID_PROPERTY_NAME = "uuid";
+
+ private static final ConcurrentMap<String, InMemoryRepositorySource> sources = new ConcurrentHashMap<String, InMemoryRepositorySource>();
+ private static final ReadWriteLock sourcesLock = new ReentrantReadWriteLock();
+
+ /**
+ * Get the names of the in-memory repository sources that are currently registered
+ *
+ * @return the unmodifiable set of names
+ */
+ public static Set<String> getSourceNames() {
+ Lock lock = sourcesLock.readLock();
+ try {
+ lock.lock();
+ return Collections.unmodifiableSet(sources.keySet());
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Get the source with the supplied name.
+ *
+ * @param name the name
+ * @return the source, or null if there is no source with the supplied name
+ */
+ public static InMemoryRepositorySource getSource( String name ) {
+ Lock lock = sourcesLock.readLock();
+ try {
+ lock.lock();
+ return sources.get(name);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @GuardedBy( "sourcesLock" )
+ private String name;
+ @GuardedBy( "this" )
+ private String jndiName;
+ private final AtomicInteger retryLimit = new AtomicInteger(0);
+ private UUID rootNodeUuid = UUID.randomUUID();
+ private CachePolicy defaultCachePolicy;
+ private String configurationName;
+ private transient InMemoryRepository repository;
+
+ /**
+ * Create a repository source instance.
+ */
+ public InMemoryRepositorySource() {
+ }
+
+ /**
+ * Get the default cache policy for this source, or null if the global default cache policy should be used
+ *
+ * @return the default cache policy, or null if this source has no explicit default cache policy
+ */
+ public CachePolicy getDefaultCachePolicy() {
+ return defaultCachePolicy;
+ }
+
+ /**
+ * @param defaultCachePolicy Sets defaultCachePolicy to the specified value.
+ */
+ public void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
+ this.defaultCachePolicy = defaultCachePolicy;
+ }
+
+ /**
+ * @return rootNodeUuid
+ */
+ public UUID getRootNodeUuid() {
+ return this.rootNodeUuid;
+ }
+
+ /**
+ * @param rootNodeUuid Sets rootNodeUuid to the specified value.
+ */
+ public void setRootNodeUuid( UUID rootNodeUuid ) {
+ this.rootNodeUuid = rootNodeUuid != null ? rootNodeUuid : UUID.randomUUID();
+ }
+
+ /**
+ * If you use this to set a JNDI name, this source will be bound to that name using the default {@link InitialContext}. You
+ * can also do this manually if you have additional requirements.
+ *
+ * @param name the JNDI name
+ * @throws NamingException if there is a problem registering this object
+ * @see #getJndiName()
+ */
+ public void setJndiName( String name ) throws NamingException {
+ setJndiName(name, null);
+ }
+
+ /**
+ * Register this source in JNDI under the supplied name using the supplied context. to set a JNDI name, this source will be
+ * bound to that name using the default {@link InitialContext}. You can also do this manually if you have additional
+ * requirements.
+ *
+ * @param name the JNDI name, or null if this object is to no longer be registered
+ * @param context the JNDI context, or null if the {@link InitialContext} should be used
+ * @throws NamingException if there is a problem registering this object
+ * @see #getJndiName()
+ */
+ public synchronized void setJndiName( String name,
+ Context context ) throws NamingException {
+ ArgCheck.isNotNull(name, "name");
+ if (context == null) context = new InitialContext();
+
+ // First register in JNDI under the new name ...
+ if (name != null) {
+ context.bind(name, this);
+ }
+ // Second, unregister from JNDI if there is already a name ...
+ if (jndiName != null && !jndiName.equals(name)) {
+ context.unbind(jndiName);
+ }
+ // Record the new name ...
+ this.jndiName = name;
+ }
+
+ /**
+ * Gets the JNDI name this source is bound to. Only valid if you used setJNDIName to bind it.
+ *
+ * @return the JNDI name, or null if it is not bound in JNDI
+ * @see #setJndiName(String)
+ */
+ public synchronized String getJndiName() {
+ return jndiName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ Lock lock = sourcesLock.readLock();
+ try {
+ lock.lock();
+ return this.name;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * @param name Sets name to the specified value.
+ * @return true if the name was changed, or false if an existing instance already exists with that name
+ */
+ public boolean setName( String name ) {
+ Lock lock = sourcesLock.writeLock();
+ try {
+ lock.lock();
+ // Determine if this name is allowed ...
+ if (sources.containsKey(name)) return false;
+
+ // Remove this object under its current name
+ if (this.name != null) {
+ sources.remove(this.name);
+ }
+ // Register this object under the new name
+ this.name = name;
+ sources.put(this.name, this);
+ return true;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getRetryLimit() {
+ return retryLimit.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setRetryLimit( int limit ) {
+ retryLimit.set(limit);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized RepositoryConnection getConnection() {
+ if (this.repository == null) {
+ repository = new InMemoryRepository(configurationName, this.rootNodeUuid);
+ }
+ return new InMemoryRepositoryConnection(this, this.repository);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Reference getReference() {
+ String className = getClass().getName();
+ String factoryClassName = className;
+ return new Reference(className, new StringRefAddr("DnaConnectorInMemoryRepositorySource", getName()), factoryClassName,
+ null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getObjectInstance( Object obj,
+ javax.naming.Name name,
+ Context nameCtx,
+ Hashtable<?, ?> environment ) {
+ if (obj instanceof Reference) {
+ Reference ref = (Reference)obj;
+ if (ref.getClassName().equals(getClass().getName())) {
+ RefAddr addr = ref.get("DnaConnectorInMemoryRepositorySource");
+ return InMemoryRepositorySource.getSource((String)addr.getContent());
+ }
+ }
+ return null;
+ }
+
+}
Added: trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/Node.java
===================================================================
--- trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/Node.java (rev 0)
+++ trunk/connectors/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/Node.java 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,169 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.inmemory;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.Path;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.PropertyFactory;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+
+/**
+ * @author Randall Hauch
+ */
+@NotThreadSafe
+public class Node {
+
+ private final UUID uuid;
+ private Node parent;
+ private Path.Segment name;
+ private final Map<Name, Property> properties = new HashMap<Name, Property>();
+ private final List<Node> children = new LinkedList<Node>();
+
+ public Node( UUID uuid ) {
+ assert uuid != null;
+ this.uuid = uuid;
+ }
+
+ /**
+ * @return uuid
+ */
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ /**
+ * @return name
+ */
+ public Path.Segment getName() {
+ return name;
+ }
+
+ /**
+ * @param name Sets name to the specified value.
+ */
+ protected void setName( Path.Segment name ) {
+ this.name = name;
+ }
+
+ /**
+ * @return parent
+ */
+ public Node getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent Sets parent to the specified value.
+ */
+ protected void setParent( Node parent ) {
+ this.parent = parent;
+ }
+
+ /**
+ * @return children
+ */
+ protected List<Node> getChildren() {
+ return children;
+ }
+
+ /**
+ * @return properties
+ */
+ protected Map<Name, Property> getProperties() {
+ return properties;
+ }
+
+ public Node setProperty( Property property ) {
+ if (property != null) {
+ this.properties.put(property.getName(), property);
+ }
+ return this;
+ }
+
+ public Node setProperty( ExecutionEnvironment env,
+ String name,
+ Object... values ) {
+ PropertyFactory propertyFactory = env.getPropertyFactory();
+ Name propertyName = env.getValueFactories().getNameFactory().create(name);
+ return setProperty(propertyFactory.create(propertyName, values));
+ }
+
+ public Property getProperty( ExecutionEnvironment env,
+ String name ) {
+ Name propertyName = env.getValueFactories().getNameFactory().create(name);
+ return getProperty(propertyName);
+ }
+
+ public Property getProperty( Name name ) {
+ return this.properties.get(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return uuid.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (obj instanceof Node) {
+ Node that = (Node)obj;
+ if (!this.getUuid().equals(that.getUuid())) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (this.name == null) {
+ sb.append("");
+ } else {
+ sb.append(this.name);
+ }
+ sb.append(" (").append(uuid).append(")");
+ return sb.toString();
+ }
+}
Added: trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.properties
===================================================================
--- trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.properties (rev 0)
+++ trunk/connectors/dna-connector-inmemory/src/main/resources/org/jboss/dna/connector/inmemory/InMemoryConnectorI18n.properties 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+connectorName = In-Memory Connector
+nodeDoesNotExist = Could not find an existing node at {0}
\ No newline at end of file
Added: trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryTest.java
===================================================================
--- trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryTest.java (rev 0)
+++ trunk/connectors/dna-connector-inmemory/src/test/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryTest.java 2008-06-30 21:32:40 UTC (rev 317)
@@ -0,0 +1,351 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.inmemory;
+
+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.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+import org.jboss.dna.spi.graph.Name;
+import org.jboss.dna.spi.graph.NameFactory;
+import org.jboss.dna.spi.graph.PathFactory;
+import org.jboss.dna.spi.graph.Property;
+import org.jboss.dna.spi.graph.PropertyFactory;
+import org.jboss.dna.spi.graph.ValueFactories;
+import org.jboss.dna.spi.graph.ValueFactory;
+import org.jboss.dna.spi.graph.connection.ExecutionEnvironment;
+import org.jboss.dna.spi.graph.impl.BasicNamespaceRegistry;
+import org.jboss.dna.spi.graph.impl.BasicPropertyFactory;
+import org.jboss.dna.spi.graph.impl.StandardValueFactories;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class InMemoryRepositoryTest {
+
+ private InMemoryRepository repository;
+ private String name;
+ private UUID rootUuid;
+ private ValueFactories valueFactories;
+ private PathFactory pathFactory;
+ private NameFactory nameFactory;
+ private PropertyFactory propertyFactory;
+ @Mock
+ private ExecutionEnvironment env;
+
+ @Before
+ public void beforeEach() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ valueFactories = new StandardValueFactories(new BasicNamespaceRegistry());
+ pathFactory = valueFactories.getPathFactory();
+ nameFactory = valueFactories.getNameFactory();
+ propertyFactory = new BasicPropertyFactory(valueFactories);
+ name = "Test repository";
+ rootUuid = UUID.randomUUID();
+ repository = new InMemoryRepository(name, rootUuid);
+ stub(env.getValueFactories()).toReturn(valueFactories);
+ stub(env.getPropertyFactory()).toReturn(propertyFactory);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowNullNameInConstructor() {
+ new InMemoryRepository(null, rootUuid);
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowBlankNameInConstructor() {
+ new InMemoryRepository(" \t ", rootUuid);
+ }
+
+ @Test
+ public void shouldHaveLock() {
+ assertThat(repository.getLock(), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldHaveRootNodeAfterInstantiating() {
+ assertThat(repository.getRoot(), is(notNullValue()));
+ }
+
+ @Test
+ public void shouldHaveNameAfterInstantiating() {
+ assertThat(repository.getName(), is(name));
+ }
+
+ @Test
+ public void shouldHaveRootNodeWithRootUuid() {
+ assertThat(repository.getRoot().getUuid(), is(rootUuid));
+ }
+
+ @Test
+ public void shouldGenerateUuids() {
+ Set<UUID> uuids = new HashSet<UUID>();
+ for (int i = 0; i != 100; ++i) {
+ assertThat(uuids.add(repository.generateUuid()), is(true));
+ }
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowRootToBeRemoved() {
+ repository.removeNode(env, repository.getRoot());
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowRootToBeMoved() {
+ Node node = mock(Node.class);
+ repository.moveNode(env, repository.getRoot(), node);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowNodeToBeMovedUsingNullEnvironment() {
+ Node node = mock(Node.class);
+ Node newParent = mock(Node.class);
+ repository.moveNode(null, node, newParent);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowNullNodeToBeMoved() {
+ Node newParent = mock(Node.class);
+ repository.moveNode(env, null, newParent);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowNodeToBeRemovedUsingNullEnvironment() {
+ Node node = mock(Node.class);
+ repository.removeNode(null, node);
+ }
+
+ @Test( expected = AssertionError.class )
+ public void shouldNotAllowNullNodeToBeRemoved() {
+ repository.removeNode(env, null);
+ }
+
+ @Test
+ public void shouldCreateNodesByPath() {
+ Name name_a = nameFactory.create("a");
+ Node node_a = repository.createNode(env, repository.getRoot(), name_a);
+ assertThat(node_a, is(notNullValue()));
+ assertThat(node_a.getParent(), is(repository.getRoot()));
+ assertThat(node_a.getName().getName(), is(name_a));
+ assertThat(node_a.getName().hasIndex(), is(false));
+
+ Name name_b = nameFactory.create("b");
+ Node node_b = repository.createNode(env, node_a, name_b);
+ assertThat(node_b, is(notNullValue()));
+ assertThat(node_b.getParent(), is(node_a));
+ assertThat(node_b.getName().getName(), is(name_b));
+ assertThat(node_b.getName().hasIndex(), is(false));
+
+ Name name_c = nameFactory.create("c");
+ Node node_c = repository.createNode(env, node_b, name_c);
+ assertThat(node_c, is(notNullValue()));
+ assertThat(node_c.getParent(), is(node_b));
+ assertThat(node_c.getName().getName(), is(name_c));
+ assertThat(node_c.getName().hasIndex(), is(false));
+
+ assertThat(repository.getNodesByUuid().size(), is(4));
+ assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/a/b/c")), is(sameInstance(node_c)));
+ }
+
+ @Test
+ public void shouldNotFindNodesThatDoNotExist() {
+ Node node_a = repository.createNode(env, repository.getRoot(), nameFactory.create("a"));
+ Node node_b = repository.createNode(env, node_a, nameFactory.create("b"));
+ /*Node node_c =*/repository.createNode(env, node_b, nameFactory.create("c"));
+
+ assertThat(repository.getNodesByUuid().size(), is(4));
+ assertThat(repository.getNode(pathFactory.create("/a[1]")), is(nullValue()));
+ assertThat(repository.getNode(pathFactory.create("/d")), is(nullValue()));
+ }
+
+ @Test
+ public void shouldCorrectlyManageIndexesOfSiblingsWithSameNames() {
+ Name name_a1 = nameFactory.create("a");
+ Node node_a1 = repository.createNode(env, repository.getRoot(), name_a1);
+ assertThat(node_a1, is(notNullValue()));
+ assertThat(node_a1.getParent(), is(repository.getRoot()));
+ assertThat(node_a1.getName().getName(), is(name_a1));
+ assertThat(node_a1.getName().hasIndex(), is(false));
+
+ Name name_a2 = nameFactory.create("a");
+ Node node_a2 = repository.createNode(env, repository.getRoot(), name_a2);
+ assertThat(node_a2, is(notNullValue()));
+ assertThat(node_a2.getParent(), is(repository.getRoot()));
+ assertThat(node_a2.getName().getName(), is(name_a2));
+ assertThat(node_a2.getName().hasIndex(), is(true));
+ assertThat(node_a2.getName().getIndex(), is(2));
+
+ // node 1 should now have an index ...
+ assertThat(node_a1.getName().getIndex(), is(1));
+
+ // Add another node without the same name ...
+ Name name_b = nameFactory.create("b");
+ Node node_b = repository.createNode(env, repository.getRoot(), name_b);
+ assertThat(node_b, is(notNullValue()));
+ assertThat(node_b.getParent(), is(repository.getRoot()));
+ assertThat(node_b.getName().getName(), is(name_b));
+ assertThat(node_b.getName().hasIndex(), is(false));
+
+ // Add a third node with the same name ...
+ Name name_a3 = nameFactory.create("a");
+ Node node_a3 = repository.createNode(env, repository.getRoot(), name_a3);
+ assertThat(node_a3, is(notNullValue()));
+ assertThat(node_a3.getParent(), is(repository.getRoot()));
+ assertThat(node_a3.getName().getName(), is(name_a3));
+ assertThat(node_a3.getName().hasIndex(), is(true));
+ assertThat(node_a3.getName().getIndex(), is(3));
+
+ // Check the number of children ...
+ assertThat(repository.getRoot().getChildren().size(), is(4));
+ assertThat(repository.getRoot().getChildren(), hasItems(node_a1, node_a2, node_b, node_a3));
+ assertThat(repository.getNodesByUuid().size(), is(5));
+ assertThat(repository.getNode(pathFactory.create("/a[1]")), is(sameInstance(node_a1)));
+ assertThat(repository.getNode(pathFactory.create("/a[2]")), is(sameInstance(node_a2)));
+ assertThat(repository.getNode(pathFactory.create("/a[3]")), is(sameInstance(node_a3)));
+ assertThat(repository.getNode(pathFactory.create("/b")), is(sameInstance(node_b)));
+
+ // Removing a node with the same name will reduce the index ...
+ repository.removeNode(env, node_a2);
+ assertThat(repository.getRoot().getChildren().size(), is(3));
+ assertThat(repository.getRoot().getChildren(), hasItems(node_a1, node_b, node_a3));
+ assertThat(node_a1.getName().getIndex(), is(1));
+ assertThat(node_b.getName().hasIndex(), is(false));
+ assertThat(node_a3.getName().getIndex(), is(2));
+
+ // Removing a node with the same name will reduce the index ...
+ repository.removeNode(env, node_a1);
+ assertThat(repository.getRoot().getChildren().size(), is(2));
+ assertThat(repository.getRoot().getChildren(), hasItems(node_b, node_a3));
+ assertThat(node_b.getName().hasIndex(), is(false));
+ assertThat(node_a3.getName().hasIndex(), is(false));
+ assertThat(repository.getNodesByUuid().size(), is(3));
+ }
+
+ @Test
+ public void shouldMoveNodes() {
+ Node root = repository.getRoot();
+ Node node_a = repository.createNode(env, root, nameFactory.create("a"));
+ Node node_b = repository.createNode(env, node_a, nameFactory.create("b"));
+ Node node_c = repository.createNode(env, node_b, nameFactory.create("c"));
+ Node node_d = repository.createNode(env, root, nameFactory.create("d"));
+ Node node_e = repository.createNode(env, node_d, nameFactory.create("e"));
+ Node node_b2 = repository.createNode(env, node_d, nameFactory.create("b"));
+
+ assertThat(repository.getNodesByUuid().size(), is(7));
+ assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/a/b/c")), is(sameInstance(node_c)));
+ assertThat(repository.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
+ assertThat(repository.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
+ assertThat(repository.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
+
+ repository.moveNode(env, node_b, node_d);
+
+ assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
+ assertThat(repository.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
+ assertThat(repository.getNode(pathFactory.create("/d/b[1]")), is(sameInstance(node_b2)));
+ assertThat(repository.getNode(pathFactory.create("/d/b[2]")), is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/d/b[2]/c")), is(sameInstance(node_c)));
+
+ repository.moveNode(env, node_b, node_e);
+
+ assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
+ assertThat(repository.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
+ assertThat(repository.getNode(pathFactory.create("/d/e/b")), is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/d/e/b/c")), is(sameInstance(node_c)));
+ assertThat(repository.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
+ }
+
+ @Test
+ public void shouldCopyNodes() {
+ Node root = repository.getRoot();
+ Node node_a = repository.createNode(env, root, nameFactory.create("a"));
+ Node node_b = repository.createNode(env, node_a, nameFactory.create("b"));
+ Node node_c = repository.createNode(env, node_b, nameFactory.create("c"));
+ Node node_d = repository.createNode(env, root, nameFactory.create("d"));
+ Node node_e = repository.createNode(env, node_d, nameFactory.create("e"));
+ Node node_b2 = repository.createNode(env, node_d, nameFactory.create("b"));
+
+ ValueFactory<String> stringFactory = valueFactories.getStringFactory();
+ Name propertyName = nameFactory.create("something");
+ Property property = propertyFactory.create(propertyName, stringFactory.create("Worth the wait"));
+ node_b.getProperties().put(propertyName, property);
+
+ assertThat(repository.getNodesByUuid().size(), is(7));
+ assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/a/b/c")), is(sameInstance(node_c)));
+ assertThat(repository.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
+ assertThat(repository.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
+ assertThat(repository.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
+
+ assertThat(repository.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+
+ repository.copyNode(env, node_b, node_d, true);
+
+ assertThat(repository.getNodesByUuid().size(), is(9));
+ assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+ assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+ assertThat(repository.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
+ assertThat(repository.getNode(pathFactory.create("/a/b/c")), is(sameInstance(node_c)));
+ assertThat(repository.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
+ assertThat(repository.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
+ assertThat(repository.getNode(pathFactory.create("/d/b[1]")), is(sameInstance(node_b2)));
+ assertThat(repository.getNode(pathFactory.create("/d/b[2]")), is(notNullValue()));
+ assertThat(repository.getNode(pathFactory.create("/d/b[2]/c")), is(notNullValue()));
+
+ assertThat(repository.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+ assertThat(repository.getNode(pathFactory.create("/d/b[2]")).getProperties().get(propertyName), is(property));
+ }
+
+ @Test
+ public void shouldCreateRepositoryStructure() {
+ repository.createNode(env, "/a").setProperty(env, "name", "value").setProperty(env, "desc", "Some description");
+ repository.createNode(env, "/a/b").setProperty(env, "name", "value2").setProperty(env, "desc", "Some description 2");
+ assertThat(repository.getNode(env, "/a").getProperty(env, "name").getValuesAsArray(), is(new Object[] {"value"}));
+ assertThat(repository.getNode(env, "/a").getProperty(env, "desc").getValuesAsArray(),
+ is(new Object[] {"Some description"}));
+ assertThat(repository.getNode(env, "/a/b").getProperty(env, "name").getValuesAsArray(), is(new Object[] {"value2"}));
+ assertThat(repository.getNode(env, "/a/b").getProperty(env, "desc").getValuesAsArray(),
+ is(new Object[] {"Some description 2"}));
+ }
+}
15 years, 9 months
DNA SVN: r316 - trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-06-30 17:31:22 -0400 (Mon, 30 Jun 2008)
New Revision: 316
Added:
trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/CompositeCommand.java
Log:
Added composite command.
Added: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/CompositeCommand.java
===================================================================
--- trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/CompositeCommand.java (rev 0)
+++ trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/CompositeCommand.java 2008-06-30 21:31:22 UTC (rev 316)
@@ -0,0 +1,30 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.spi.graph.commands;
+
+/**
+ * A command that is a composition of other commands.
+ *
+ * @author Randall Hauch
+ */
+public interface CompositeCommand extends GraphCommand, Iterable<GraphCommand> {
+}
Property changes on: trunk/dna-spi/src/main/java/org/jboss/dna/spi/graph/commands/CompositeCommand.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
15 years, 9 months
DNA SVN: r315 - in trunk/dna-common/src: test/java/org/jboss/dna/common/util and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-06-27 17:03:53 -0400 (Fri, 27 Jun 2008)
New Revision: 315
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java
trunk/dna-common/src/test/java/org/jboss/dna/common/util/ReflectionTest.java
Log:
DNA-115 - Create federation service
http://jira.jboss.com/jira/browse/DNA-115
Updated reflection utility to execute getter and setter, based upon JavaBean property name.
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java 2008-06-27 21:01:40 UTC (rev 314)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/util/Reflection.java 2008-06-27 21:03:53 UTC (rev 315)
@@ -21,14 +21,17 @@
*/
package org.jboss.dna.common.util;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.regex.Pattern;
/**
@@ -219,10 +222,13 @@
* Find the method on the target class that matches the supplied method name.
*
* @param methodName the name of the method that is to be found.
+ * @param caseSensitive true if the method name supplied should match case-sensitively, or false if case does not matter
* @return the Method objects that have a matching name, or an empty array if there are no methods that have a matching name.
*/
- public Method[] findMethods( String methodName ) {
- return findMethods(Pattern.compile(methodName));
+ public Method[] findMethods( String methodName,
+ boolean caseSensitive ) {
+ Pattern pattern = caseSensitive ? Pattern.compile(methodName) : Pattern.compile(methodName, Pattern.CASE_INSENSITIVE);
+ return findMethods(pattern);
}
/**
@@ -247,10 +253,13 @@
* Find the method on the target class that matches the supplied method name.
*
* @param methodName the name of the method that is to be found.
+ * @param caseSensitive true if the method name supplied should match case-sensitively, or false if case does not matter
* @return the first Method object found that has a matching name, or null if there are no methods that have a matching name.
*/
- public Method findFirstMethod( String methodName ) {
- return findFirstMethod(Pattern.compile(methodName));
+ public Method findFirstMethod( String methodName,
+ boolean caseSensitive ) {
+ Pattern pattern = caseSensitive ? Pattern.compile(methodName) : Pattern.compile(methodName, Pattern.CASE_INSENSITIVE);
+ return findFirstMethod(pattern);
}
/**
@@ -271,6 +280,104 @@
}
/**
+ * Find and execute the best method on the target class that matches the signature specified with one of the specified names
+ * and the list of arguments. If no such method is found, a NoSuchMethodException is thrown.
+ * <P>
+ * This method is unable to find methods with signatures that include both primitive arguments <i>and</i> arguments that are
+ * instances of <code>Number</code> or its subclasses.
+ * </p>
+ *
+ * @param methodNames the names of the methods that are to be invoked, in the order they are to be tried
+ * @param target the object on which the method is to be invoked
+ * @param arguments the array of Object instances that correspond to the arguments passed to the method.
+ * @return the Method object that references the method that satisfies the requirements, or null if no satisfactory method
+ * could be found.
+ * @throws NoSuchMethodException if a matching method is not found.
+ * @throws SecurityException if access to the information is denied.
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ * @throws IllegalArgumentException
+ */
+ public Object invokeBestMethodOnTarget( String[] methodNames,
+ Object target,
+ Object... arguments )
+ throws NoSuchMethodException, SecurityException, IllegalArgumentException, IllegalAccessException,
+ InvocationTargetException {
+ Class<?>[] argumentClasses = buildArgumentClasses(arguments);
+ int remaining = methodNames.length;
+ Object result = null;
+ for (String methodName : methodNames) {
+ --remaining;
+ try {
+ Method method = findBestMethodWithSignature(methodName, argumentClasses);
+ result = method.invoke(target, arguments);
+ break;
+ } catch (NoSuchMethodException e) {
+ if (remaining == 0) throw e;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Find and execute the best setter method on the target class for the supplied property name and the supplied list of
+ * arguments. If no such method is found, a NoSuchMethodException is thrown.
+ * <P>
+ * This method is unable to find methods with signatures that include both primitive arguments <i>and</i> arguments that are
+ * instances of <code>Number</code> or its subclasses.
+ * </p>
+ *
+ * @param javaPropertyName the name of the property whose setter is to be invoked, in the order they are to be tried
+ * @param target the object on which the method is to be invoked
+ * @param argument the new value for the property
+ * @return the result of the setter method, which is typically null (void)
+ * @throws NoSuchMethodException if a matching method is not found.
+ * @throws SecurityException if access to the information is denied.
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ * @throws IllegalArgumentException
+ */
+ public Object invokeSetterMethodOnTarget( String javaPropertyName,
+ Object target,
+ Object argument )
+ throws NoSuchMethodException, SecurityException, IllegalArgumentException, IllegalAccessException,
+ InvocationTargetException {
+ String[] methodNamesArray = findMethodNames("set" + javaPropertyName);
+ return invokeBestMethodOnTarget(methodNamesArray, target, argument);
+ }
+
+ /**
+ * Find and execute the getter method on the target class for the supplied property name. If no such method is found, a
+ * NoSuchMethodException is thrown.
+ *
+ * @param javaPropertyName the name of the property whose getter is to be invoked, in the order they are to be tried
+ * @param target the object on which the method is to be invoked
+ * @return the property value (the result of the getter method call)
+ * @throws NoSuchMethodException if a matching method is not found.
+ * @throws SecurityException if access to the information is denied.
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ * @throws IllegalArgumentException
+ */
+ public Object invokeGetterMethodOnTarget( String javaPropertyName,
+ Object target )
+ throws NoSuchMethodException, SecurityException, IllegalArgumentException, IllegalAccessException,
+ InvocationTargetException {
+ String[] methodNamesArray = findMethodNames("get" + javaPropertyName);
+ return invokeBestMethodOnTarget(methodNamesArray, target);
+ }
+
+ protected String[] findMethodNames( String methodName ) {
+ Method[] methods = findMethods(methodName, false);
+ Set<String> methodNames = new HashSet<String>();
+ for (Method method : methods) {
+ String actualMethodName = method.getName();
+ methodNames.add(actualMethodName);
+ }
+ return methodNames.toArray(new String[methodNames.size()]);
+ }
+
+ /**
* Find the best method on the target class that matches the signature specified with the specified name and the list of
* arguments. This method first attempts to find the method with the specified arguments; if no such method is found, a
* NoSuchMethodException is thrown.
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/util/ReflectionTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/util/ReflectionTest.java 2008-06-27 21:01:40 UTC (rev 314)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/util/ReflectionTest.java 2008-06-27 21:03:53 UTC (rev 315)
@@ -132,12 +132,12 @@
@Test
public void shouldFindMethodsWithExactMatchingName() {
- Method[] stringMethods = stringReflection.findMethods("indexOf");
+ Method[] stringMethods = stringReflection.findMethods("indexOf", true);
assertThat(stringMethods.length, is(4));
for (Method method : stringMethods) {
assertThat(method.getName(), is("indexOf"));
}
- stringMethods = stringReflection.findMethods("length");
+ stringMethods = stringReflection.findMethods("length", true);
assertThat(stringMethods.length, is(1));
for (Method method : stringMethods) {
assertThat(method.getName(), is("length"));
@@ -146,12 +146,12 @@
@Test
public void shouldFindMethodsWithNameMatchingRegularExpression() {
- Method[] stringMethods = stringReflection.findMethods("indexO.");
+ Method[] stringMethods = stringReflection.findMethods("indexO.", true);
assertThat(stringMethods.length, is(4));
for (Method method : stringMethods) {
assertThat(method.getName(), is("indexOf"));
}
- stringMethods = stringReflection.findMethods(".+gth");
+ stringMethods = stringReflection.findMethods(".+gth", true);
assertThat(stringMethods.length, is(1));
for (Method method : stringMethods) {
assertThat(method.getName(), is("length"));
@@ -160,8 +160,8 @@
@Test
public void shouldNotFindMethodsWhenThereAreNoMethodsWithThatName() {
- assertThat(stringReflection.findMethods("size").length, is(0));
- assertThat(stringListReflection.findMethods("argleBargle").length, is(0));
+ assertThat(stringReflection.findMethods("size", true).length, is(0));
+ assertThat(stringListReflection.findMethods("argleBargle", true).length, is(0));
}
}
15 years, 9 months
DNA SVN: r314 - trunk.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-06-27 17:01:40 -0400 (Fri, 27 Jun 2008)
New Revision: 314
Modified:
trunk/pom.xml
Log:
Corrected contributor fragment, which can't have id elements.
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2008-06-26 23:38:39 UTC (rev 313)
+++ trunk/pom.xml 2008-06-27 21:01:40 UTC (rev 314)
@@ -88,7 +88,6 @@
<contributors>
<contributor>
<name>Greg Haber</name>
- <id>ghaber</id>
<organization>JBoss, a division of Red Hat</organization>
<timezone>-5</timezone>
</contributor>
15 years, 9 months
DNA SVN: r313 - trunk.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2008-06-26 19:38:39 -0400 (Thu, 26 Jun 2008)
New Revision: 313
Modified:
trunk/pom.xml
Log:
Added project inception year to parent POM
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2008-06-26 21:25:36 UTC (rev 312)
+++ trunk/pom.xml 2008-06-26 23:38:39 UTC (rev 313)
@@ -6,6 +6,7 @@
<packaging>pom</packaging>
<name>JBoss DNA</name>
<url>http://www.jboss.org/dna</url>
+ <inceptionYear>2008</inceptionYear>
<description>
JBoss DNA provides tools for working with JCR repositories.
</description>
15 years, 10 months
DNA SVN: r312 - in trunk/sequencers: dna-sequencer-zip and 22 other directories.
by dna-commits@lists.jboss.org
Author: mathwizard
Date: 2008-06-26 17:25:36 -0400 (Thu, 26 Jun 2008)
New Revision: 312
Added:
trunk/sequencers/dna-sequencer-zip/
trunk/sequencers/dna-sequencer-zip/.classpath
trunk/sequencers/dna-sequencer-zip/.project
trunk/sequencers/dna-sequencer-zip/pom.xml
trunk/sequencers/dna-sequencer-zip/src/
trunk/sequencers/dna-sequencer-zip/src/main/
trunk/sequencers/dna-sequencer-zip/src/main/java/
trunk/sequencers/dna-sequencer-zip/src/main/java/org/
trunk/sequencers/dna-sequencer-zip/src/main/java/org/jboss/
trunk/sequencers/dna-sequencer-zip/src/main/java/org/jboss/dna/
trunk/sequencers/dna-sequencer-zip/src/main/java/org/jboss/dna/sequencer/
trunk/sequencers/dna-sequencer-zip/src/main/java/org/jboss/dna/sequencer/zip/
trunk/sequencers/dna-sequencer-zip/src/main/java/org/jboss/dna/sequencer/zip/ZipSequencer.java
trunk/sequencers/dna-sequencer-zip/src/main/resources/
trunk/sequencers/dna-sequencer-zip/src/main/resources/org/
trunk/sequencers/dna-sequencer-zip/src/main/resources/org/jboss/
trunk/sequencers/dna-sequencer-zip/src/main/resources/org/jboss/dna/
trunk/sequencers/dna-sequencer-zip/src/main/resources/org/jboss/dna/sequencer/
trunk/sequencers/dna-sequencer-zip/src/main/resources/org/jboss/dna/sequencer/zip/
trunk/sequencers/dna-sequencer-zip/src/main/resources/org/jboss/dna/sequencer/zip/zip.cnd
trunk/sequencers/dna-sequencer-zip/src/test/
trunk/sequencers/dna-sequencer-zip/src/test/java/
trunk/sequencers/dna-sequencer-zip/src/test/java/org/
trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/
trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/
trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/
trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/
trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/PropertyClassTest.java
trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/SequencingOutputTestClass.java
trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/ZipSequencerTest.java
trunk/sequencers/dna-sequencer-zip/src/test/resources/
trunk/sequencers/dna-sequencer-zip/src/test/resources/testzip.zip
Log:
[DNA:63] Added ZIP file sequencer
Added: trunk/sequencers/dna-sequencer-zip/.classpath
===================================================================
--- trunk/sequencers/dna-sequencer-zip/.classpath (rev 0)
+++ trunk/sequencers/dna-sequencer-zip/.classpath 2008-06-26 21:25:36 UTC (rev 312)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
Added: trunk/sequencers/dna-sequencer-zip/.project
===================================================================
--- trunk/sequencers/dna-sequencer-zip/.project (rev 0)
+++ trunk/sequencers/dna-sequencer-zip/.project 2008-06-26 21:25:36 UTC (rev 312)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>dna-sequencer-zip</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.maven.ide.eclipse.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.maven.ide.eclipse.maven2Nature</nature>
+ </natures>
+</projectDescription>
Added: trunk/sequencers/dna-sequencer-zip/pom.xml
===================================================================
--- trunk/sequencers/dna-sequencer-zip/pom.xml (rev 0)
+++ trunk/sequencers/dna-sequencer-zip/pom.xml 2008-06-26 21:25:36 UTC (rev 312)
@@ -0,0 +1,54 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>dna</artifactId>
+ <groupId>org.jboss.dna</groupId>
+ <version>0.2-SNAPSHOT</version>
+ <relativePath>../..</relativePath>
+ </parent>
+ <!-- The groupId and version values are inherited from parent -->
+ <artifactId>dna-sequencer-zip</artifactId>
+ <packaging>jar</packaging>
+ <name>JBoss DNA ZIP Sequencer</name>
+ <description>JBoss DNA Sequencer that processes zip files and extracts content to repository</description>
+ <url>http://labs.jboss.org/dna</url>
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>${dna-version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit-dep</artifactId>
+ <version>4.4</version>
+ </dependency>
+ <!--
+ Logging (require SLF4J API for compiling, but use Log4J and its SLF4J binding for testing)
+ -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
Added: trunk/sequencers/dna-sequencer-zip/src/main/java/org/jboss/dna/sequencer/zip/ZipSequencer.java
===================================================================
--- trunk/sequencers/dna-sequencer-zip/src/main/java/org/jboss/dna/sequencer/zip/ZipSequencer.java (rev 0)
+++ trunk/sequencers/dna-sequencer-zip/src/main/java/org/jboss/dna/sequencer/zip/ZipSequencer.java 2008-06-26 21:25:36 UTC (rev 312)
@@ -0,0 +1,72 @@
+/*
+ * 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.sequencer.zip;
+
+import org.jboss.dna.spi.sequencers.StreamSequencer;
+import org.jboss.dna.spi.sequencers.SequencerOutput;
+import org.jboss.dna.common.monitor.ProgressMonitor;
+
+import java.io.*;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipEntry;
+
+/**
+ * @author Michael Trezzi
+ */
+public class ZipSequencer implements StreamSequencer {
+ public void sequence(InputStream stream, SequencerOutput output, ProgressMonitor progressMonitor) {
+ try {
+ ZipInputStream in = new ZipInputStream(stream);
+ ZipEntry entry = in.getNextEntry();
+ byte[] buf = new byte[1024];
+
+ // Create top-level node
+ output.setProperty("zip:content", "jcr:primaryType", "zip:content");
+ while (entry != null)
+ {
+
+ if(entry.isDirectory()) { // If entry is directory, create nt:folder node
+ output.setProperty("zip:content/"+entry.getName(), "jcr:primaryType", "nt:folder");
+ } else { // If entry is File, create nt:file
+ output.setProperty("zip:content/"+entry.getName()+"/jcr:content", "jcr:primaryType", "nt:resource" );
+ int n;
+ ByteArrayOutputStream baout = new ByteArrayOutputStream();
+ while ((n = in.read(buf, 0, 1024)) > -1) {
+ baout.write(buf, 0, n);
+ }
+ output.setProperty("zip:content/"+entry.getName()+"/jcr:content", "jcr:data", baout.toByteArray());
+ // all other nt:file properties should be generated by other sequencers (mimetype, encoding,...)
+ }
+ in.closeEntry();
+ entry = in.getNextEntry();
+
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+
+ }
+}
Added: trunk/sequencers/dna-sequencer-zip/src/main/resources/org/jboss/dna/sequencer/zip/zip.cnd
===================================================================
--- trunk/sequencers/dna-sequencer-zip/src/main/resources/org/jboss/dna/sequencer/zip/zip.cnd (rev 0)
+++ trunk/sequencers/dna-sequencer-zip/src/main/resources/org/jboss/dna/sequencer/zip/zip.cnd 2008-06-26 21:25:36 UTC (rev 312)
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+//------------------------------------------------------------------------------
+// N A M E S P A C E S
+//------------------------------------------------------------------------------
+<jcr='http://www.jcp.org/jcr/1.0'>
+<nt='http://www.jcp.org/jcr/nt/1.0'>
+<mix='http://www.jcp.org/jcr/mix/1.0'>
+<zip='http://jboss.org/dna/zip/1.0'>
+
+// ----------------------------------------------------------
+// JCR Pre-defined Mixin Types that are not loaded by default
+// ----------------------------------------------------------
+
+[mix:mimeType] mixin
+ - jcr:mimeType (string)
+ - jcr:encoding (string)
+
+
+//------------------------------------------------------------------------------
+// N O D E T Y P E S
+//------------------------------------------------------------------------------
+
+[zip:content] > nt:unstructured, mix:mimeTyped
+ + * (nt:folder)
+ + * (nt:file)
+
\ No newline at end of file
Added: trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/PropertyClassTest.java
===================================================================
--- trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/PropertyClassTest.java (rev 0)
+++ trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/PropertyClassTest.java 2008-06-26 21:25:36 UTC (rev 312)
@@ -0,0 +1,68 @@
+/*
+ * 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.sequencer.zip;
+
+import org.junit.Ignore;
+
+/**
+ * @author Michael Trezzi
+ */
+@Ignore
+public class PropertyClassTest {
+ public PropertyClassTest(String path, String name, Object value) {
+ this.path = path;
+ this.name = name;
+ this.value = value;
+ }
+
+ String path;
+ String name;
+ Object value;
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+
+
+}
Added: trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/SequencingOutputTestClass.java
===================================================================
--- trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/SequencingOutputTestClass.java (rev 0)
+++ trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/SequencingOutputTestClass.java 2008-06-26 21:25:36 UTC (rev 312)
@@ -0,0 +1,66 @@
+/*
+ * 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.sequencer.zip;
+
+import org.jboss.dna.spi.sequencers.SequencerOutput;
+import org.jboss.dna.spi.graph.*;
+import org.junit.Test;
+import org.junit.Ignore;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Michael Trezzi
+ */
+@Ignore
+public class SequencingOutputTestClass implements SequencerOutput {
+ List<PropertyClassTest> properties = new ArrayList();
+ List<PropertyClassTest> references = new ArrayList();
+
+
+
+ public ValueFactories getFactories() {
+ return null;
+ }
+
+ public NamespaceRegistry getNamespaceRegistry() {
+ return null;
+ }
+
+ public void setProperty(String nodePath, String propertyName, Object... values) {
+ System.out.println("Setting property on '"+nodePath+"' "+propertyName+":"+values[0]);
+ properties.add(new PropertyClassTest(nodePath,propertyName,values[0]));
+ }
+
+ public void setReference(String nodePath, String propertyName, String... paths) {
+ System.out.println("Setting reference on "+nodePath+" "+propertyName+":"+paths[0]);
+ references.add(new PropertyClassTest(nodePath,propertyName,paths[0]));
+ }
+
+ public void setProperty(Path nodePath, Name propertyName, Object... values) {
+ System.out.println("Setting property on "+nodePath.getString()+" "+propertyName.getString()+":"+values[0]);
+ properties.add(new PropertyClassTest(nodePath.getString(),propertyName.getString(),values[0]));
+ }
+}
Added: trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/ZipSequencerTest.java
===================================================================
--- trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/ZipSequencerTest.java (rev 0)
+++ trunk/sequencers/dna-sequencer-zip/src/test/java/org/jboss/dna/sequencer/zip/ZipSequencerTest.java 2008-06-26 21:25:36 UTC (rev 312)
@@ -0,0 +1,63 @@
+/*
+ * 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.sequencer.zip;
+
+import org.junit.Test;
+import org.junit.After;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+import java.io.InputStream;
+
+/**
+ * @author Michael Trezzi
+ */
+public class ZipSequencerTest {
+ private InputStream imageStream;
+
+ @After
+ public void afterEach() throws Exception {
+ if (imageStream != null) {
+ try {
+ imageStream.close();
+ } finally {
+ imageStream = null;
+ }
+ }
+ }
+
+ protected InputStream getTestZip( String resourcePath ) {
+ return this.getClass().getResourceAsStream("/" + resourcePath);
+ }
+
+ @Test
+ public void shouldBeAbleToExtractZip() {
+ InputStream is = getTestZip("testzip.zip");
+ ZipSequencer zs = new ZipSequencer();
+ SequencingOutputTestClass seqtest = new SequencingOutputTestClass();
+ zs.sequence(is,seqtest,null);
+
+ assertThat(seqtest.properties.get(2).getPath(), is("zip:content/test subfolder/test2.txt/jcr:content"));
+ }
+
+}
Added: trunk/sequencers/dna-sequencer-zip/src/test/resources/testzip.zip
===================================================================
(Binary files differ)
Property changes on: trunk/sequencers/dna-sequencer-zip/src/test/resources/testzip.zip
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
15 years, 10 months