Author: rhauch
Date: 2009-08-26 14:10:37 -0400 (Wed, 26 Aug 2009)
New Revision: 1174
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ObservationBus.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/SimpleRepositoryContext.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ChangeObserver.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ChangeObservers.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/NetChangeObserver.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/Observable.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/package-info.java
trunk/dna-integration-tests/pom.xml
trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryLibrary.java
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
Log:
DNA-451 RepositoryService should dynamically keep its RepositorySource instances in sync
with changes to the configuration repository
The RepositoryLibrary and RepositoryService classes were changed so that the
RepositoryService now behaves as an Observer for changes to the content in the
configuration source. If the configuration content changes, RepositoryService attempts to
update the RepositorySource instance(s) that correspond to the changed content. Of course
any removed content for a repository source causes the corresponding RepositorySource
object to be removed.
RepositoryService does not own the RepositorySource for the configuration, so it cannot
register as a listener on its own. Instead, RepositoryService is now an Observer, it must
be registered appropriately to receive the events; this is usually done by the code that
owns the configuration RepositorySource. In the case of DnaEngine, this was done by using
a (new) ObservationBus class (which allows multiple observers on the bus, but the bus is
itself an observer so that we have the multiplexing behavior) registered to receive events
from the configuration RepositorySource, and to register RepositoryService as an observer
on the bus.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ChangeObserver.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ChangeObserver.java 2009-08-25
15:04:41 UTC (rev 1173)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ChangeObserver.java 2009-08-26
18:10:37 UTC (rev 1174)
@@ -30,7 +30,7 @@
/**
* Abstract class that is used to signal that a change set has occurred. This class is
typically subclassed by those that wish to
- * observe changes in content, and {@link Observable#register(ChangeObserver) registered}
with a {@link Observable}.
+ * observe changes in content, and {@link Observable#register(Observer) registered} with
a {@link Observable}.
* <p>
* This class maintains a (weak) reference to the ChangeSource instances with which it is
registered. Therefore, the observers
* will not keep a ChangeSource from being garbage collected. And, if a change source is
garbage collected, calling
@@ -65,7 +65,7 @@
/**
* Unregister this listener from all {@link Observable sources} that it was
registered with. This is preferred over calling
- * {@link Observable#unregister(ChangeObserver)} directly.
+ * {@link Observable#unregister(Observer)} directly.
*/
public void unregister() {
doUnregister();
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ChangeObservers.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ChangeObservers.java 2009-08-25
15:04:41 UTC (rev 1173)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ChangeObservers.java 2009-08-26
18:10:37 UTC (rev 1174)
@@ -46,11 +46,11 @@
/**
* {@inheritDoc}
*
- * @see
org.jboss.dna.graph.observe.Observable#register(org.jboss.dna.graph.observe.ChangeObserver)
+ * @see
org.jboss.dna.graph.observe.Observable#register(org.jboss.dna.graph.observe.Observer)
*/
- public boolean register( ChangeObserver observer ) {
+ public boolean register( Observer observer ) {
if (observer != null && !shutdown.get() &&
observers.addIfAbsent(new ObserverReference(observer))) {
- observer.registeredWith(this);
+ if (observer instanceof ChangeObserver)
((ChangeObserver)observer).registeredWith(this);
return true;
}
return false;
@@ -59,11 +59,11 @@
/**
* {@inheritDoc}
*
- * @see
org.jboss.dna.graph.observe.Observable#unregister(org.jboss.dna.graph.observe.ChangeObserver)
+ * @see
org.jboss.dna.graph.observe.Observable#unregister(org.jboss.dna.graph.observe.Observer)
*/
- public boolean unregister( ChangeObserver observer ) {
+ public boolean unregister( Observer observer ) {
if (observer != null && observers.remove(observer)) {
- observer.unregisteredWith(this);
+ if (observer instanceof ChangeObserver)
((ChangeObserver)observer).unregisteredWith(this);
return true;
}
return false;
@@ -79,7 +79,10 @@
observers.clear();
while (iter.hasNext()) {
ObserverReference reference = iter.next();
- if (reference.get() != null) reference.get().unregisteredWith(this);
+ if (reference.get() != null) {
+ Observer observer = reference.get();
+ if (observer instanceof ChangeObserver)
((ChangeObserver)observer).unregisteredWith(this);
+ }
}
}
}
@@ -102,7 +105,7 @@
public void broadcast( Changes changes ) {
CheckArg.isNotNull(changes, "changes");
for (ObserverReference observerReference : observers) {
- ChangeObserver observer = observerReference.get();
+ Observer observer = observerReference.get();
if (observer == null) {
observers.remove(observerReference);
continue;
@@ -118,10 +121,10 @@
/**
* A {@link WeakReference} implementation that provides a valid
*/
- protected final class ObserverReference extends WeakReference<ChangeObserver>
{
+ protected final class ObserverReference extends WeakReference<Observer> {
final int hc;
- protected ObserverReference( ChangeObserver source ) {
+ protected ObserverReference( Observer source ) {
super(source);
this.hc = source.hashCode();
}
@@ -146,12 +149,12 @@
if (obj == this) return true;
if (obj instanceof ObserverReference) {
ObserverReference that = (ObserverReference)obj;
- ChangeObserver thisSource = this.get();
- ChangeObserver thatSource = that.get();
+ Observer thisSource = this.get();
+ Observer thatSource = that.get();
return thisSource == thatSource; // reference equality, not object
equality!
}
- if (obj instanceof ChangeObserver) {
- ChangeObserver that = (ChangeObserver)obj;
+ if (obj instanceof Observer) {
+ Observer that = (Observer)obj;
return this.get() == that; // reference equality, not object equality!
}
return false;
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/NetChangeObserver.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/NetChangeObserver.java 2009-08-25
15:04:41 UTC (rev 1173)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/NetChangeObserver.java 2009-08-26
18:10:37 UTC (rev 1174)
@@ -147,7 +147,7 @@
/**
* Method that is called for each net change.
*
- * @param change
+ * @param change the net change; never null
*/
protected abstract void notify( NetChange change );
@@ -228,13 +228,25 @@
return this.hc;
}
- public boolean includesAll( ChangeType... jcrEventTypes ) {
+ /**
+ * Determine whether this net change includes all of the supplied types.
+ *
+ * @param jcrEventTypes the types to check for
+ * @return true if all of the supplied events are included in this net change, or
false otherwise
+ */
+ public boolean includesAllOf( ChangeType... jcrEventTypes ) {
for (ChangeType jcrEventType : jcrEventTypes) {
if (!this.eventTypes.contains(jcrEventType)) return false;
}
return true;
}
+ /**
+ * Determine whether this net change includes any of the supplied types.
+ *
+ * @param jcrEventTypes the types to check for
+ * @return true if any of the supplied events are included in this net change, or
false otherwise
+ */
public boolean includes( ChangeType... jcrEventTypes ) {
for (ChangeType jcrEventType : jcrEventTypes) {
if (this.eventTypes.contains(jcrEventType)) return true;
@@ -242,10 +254,6 @@
return false;
}
- public boolean is( ChangeType jcrEventTypes ) {
- return this.eventTypes.contains(jcrEventTypes);
- }
-
public boolean isSameNode( NetChange that ) {
if (that == this) return true;
if (this.hc != that.hc) return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/Observable.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/Observable.java 2009-08-25
15:04:41 UTC (rev 1173)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/Observable.java 2009-08-26
18:10:37 UTC (rev 1174)
@@ -39,7 +39,7 @@
* @return true if the observer was added, or false if the observer was null, if the
observer was already registered, or if
* the observer could not be added
*/
- boolean register( ChangeObserver observer );
+ boolean register( Observer observer );
/**
* Unregister the supplied observer. This method does nothing if the observer
reference is null.
@@ -48,6 +48,6 @@
* @return true if the observer was removed, or false if the observer was null or if
the observer was not registered on this
* source
*/
- boolean unregister( ChangeObserver observer );
+ boolean unregister( Observer observer );
}
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ObservationBus.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ObservationBus.java
(rev 0)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ObservationBus.java 2009-08-26
18:10:37 UTC (rev 1174)
@@ -0,0 +1,81 @@
+/*
+ * JBoss DNA (
http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you 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.
+ *
+ * JBoss DNA 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.graph.observe;
+
+/**
+ * A simple {@link Observer} that is itself {@link Observable}. This class essentially
multiplexes the events from a single
+ * Observable to disseminate each event to multiple Observers.
+ */
+public class ObservationBus implements Observable, Observer {
+ private final ChangeObservers observers = new ChangeObservers();
+
+ public ObservationBus() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.observe.Observable#register(org.jboss.dna.graph.observe.Observer)
+ */
+ public boolean register( Observer observer ) {
+ return observers.register(observer);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.observe.Observable#unregister(org.jboss.dna.graph.observe.Observer)
+ */
+ public boolean unregister( Observer observer ) {
+ return observers.unregister(observer);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.observe.Observer#notify(org.jboss.dna.graph.observe.Changes)
+ */
+ public void notify( Changes changes ) {
+ if (changes != null) {
+ // Broadcast the changes to the registered observers ...
+ observers.broadcast(changes);
+ }
+ }
+
+ /**
+ * Determine whether this particular bus currently has any observers.
+ *
+ * @return true if there is at least one observer, or false otherwise
+ */
+ public boolean hasObservers() {
+ return !observers.isEmpty();
+ }
+
+ /**
+ * Unregister all registered observers, and mark this as no longer accepting new
registered observers.
+ */
+ public void shutdown() {
+ observers.shutdown();
+ }
+}
Property changes on:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/ObservationBus.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/package-info.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/package-info.java 2009-08-25
15:04:41 UTC (rev 1173)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/observe/package-info.java 2009-08-26
18:10:37 UTC (rev 1174)
@@ -48,7 +48,7 @@
* <p>
* Components that are to recieve notifications of changes are called
<i>observers</i>. To create an observer, simply extend
* the {@link ChangeObserver} abstract class and provide an implementation of the {@link
ChangeObserver#notify(Changes)} method.
- * Then, register the observer with an {@link Observable} using its {@link
Observable#register(ChangeObserver)} method.
+ * Then, register the observer with an {@link Observable} using its {@link
Observable#register(Observer)} method.
* The observer's {@link ChangeObserver#notify(Changes)} method will then be called
with the changes that have
* been made to the Observable.
* </p>
@@ -56,7 +56,7 @@
* it was registered. The {@link ChangeObserver} class automatically tracks which {@link
Observable} instances it is
* registered with, and calling the observer's {@link ChangeObserver#unregister()}
will unregister the observer from
* all of these Observables. Alternatively, an observer can be unregistered from a
single Observable using the
- * Observable's {@link Observable#unregister(ChangeObserver)} method.
+ * Observable's {@link Observable#unregister(Observer)} method.
* </p>
* <h3>Changes</h3>
* <p>
Modified: trunk/dna-integration-tests/pom.xml
===================================================================
--- trunk/dna-integration-tests/pom.xml 2009-08-25 15:04:41 UTC (rev 1173)
+++ trunk/dna-integration-tests/pom.xml 2009-08-26 18:10:37 UTC (rev 1174)
@@ -71,6 +71,12 @@
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
+ <artifactId>dna-connector-filesystem</artifactId>
+ <version>${pom.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
<artifactId>dna-connector-infinispan</artifactId>
<version>${pom.version}</version>
<scope>test</scope>
Modified: trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java
===================================================================
--- trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java 2009-08-25
15:04:41 UTC (rev 1173)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/DnaEngine.java 2009-08-26
18:10:37 UTC (rev 1174)
@@ -46,12 +46,14 @@
import org.jboss.dna.graph.Subgraph;
import org.jboss.dna.graph.connector.RepositoryConnection;
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositoryContext;
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.RepositorySourceException;
import org.jboss.dna.graph.mimetype.ExtensionBasedMimeTypeDetector;
import org.jboss.dna.graph.mimetype.MimeTypeDetector;
import org.jboss.dna.graph.mimetype.MimeTypeDetectorConfig;
import org.jboss.dna.graph.mimetype.MimeTypeDetectors;
+import org.jboss.dna.graph.observe.ObservationBus;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathExpression;
@@ -102,12 +104,20 @@
detectors.addDetector(new MimeTypeDetectorConfig("ExtensionDetector",
"Extension-based MIME type detector",
ExtensionBasedMimeTypeDetector.class));
+ // Create the RepositoryContext that the configuration repository source should
use ...
+ ObservationBus configurationChangeBus = new ObservationBus();
+ RepositoryContext configContext = new SimpleRepositoryContext(context,
configurationChangeBus, null);
+ final RepositorySource configSource = this.configuration.getRepositorySource();
+ configSource.initialize(configContext);
+
// Create the RepositoryService, pointing it to the configuration repository ...
Path pathToConfigurationRoot = this.configuration.getPath();
String configWorkspaceName = this.configuration.getWorkspace();
- final RepositorySource configSource = this.configuration.getRepositorySource();
repositoryService = new RepositoryService(configSource, configWorkspaceName,
pathToConfigurationRoot, context, problems);
+ // Now register the repository service to be notified of changes to the
configuration ...
+ configurationChangeBus.register(repositoryService);
+
// Create the sequencing service ...
executorService = new ScheduledThreadPoolExecutor(10); // Use a magic number for
now
sequencingService = new SequencingService();
Modified:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryLibrary.java
===================================================================
---
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryLibrary.java 2009-08-25
15:04:41 UTC (rev 1173)
+++
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryLibrary.java 2009-08-26
18:10:37 UTC (rev 1174)
@@ -25,11 +25,11 @@
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -43,10 +43,8 @@
import org.jboss.dna.graph.connector.RepositoryConnectionPool;
import org.jboss.dna.graph.connector.RepositoryContext;
import org.jboss.dna.graph.connector.RepositorySource;
-import org.jboss.dna.graph.observe.ChangeObserver;
-import org.jboss.dna.graph.observe.ChangeObservers;
-import org.jboss.dna.graph.observe.Changes;
import org.jboss.dna.graph.observe.Observable;
+import org.jboss.dna.graph.observe.ObservationBus;
import org.jboss.dna.graph.observe.Observer;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.repository.service.AbstractServiceAdministrator;
@@ -110,10 +108,10 @@
private final ServiceAdministrator administrator = new Administrator();
private final ReadWriteLock sourcesLock = new ReentrantReadWriteLock();
- private final CopyOnWriteArrayList<RepositoryConnectionPool> pools = new
CopyOnWriteArrayList<RepositoryConnectionPool>();
+ private final Map<String, RepositoryConnectionPool> pools = new
HashMap<String, RepositoryConnectionPool>();
private RepositoryConnectionFactory delegate;
private final ExecutionContext executionContext;
- private final ObservationBus observationBus = new InMemoryObservationBus();
+ private final ObservationBus observationBus = new ObservationBus();
private final RepositorySource configurationSource;
private final String configurationWorkspaceName;
private final Path pathToConfigurationRoot;
@@ -167,19 +165,26 @@
/**
* {@inheritDoc}
+ * <p>
+ * This can be used to register observers for all of the repository sources managed
by this library. The supplied observer
+ * will receive all of the changes originating from these sources.
+ * </p>
*
- * @see
org.jboss.dna.graph.observe.Observable#register(org.jboss.dna.graph.observe.ChangeObserver)
+ * @see
org.jboss.dna.graph.observe.Observable#register(org.jboss.dna.graph.observe.Observer)
*/
- public boolean register( ChangeObserver observer ) {
+ public boolean register( Observer observer ) {
return observationBus.register(observer);
}
/**
* {@inheritDoc}
+ * <p>
+ * This can be used to unregister observers for all of the repository sources managed
by this library.
+ * </p>
*
- * @see
org.jboss.dna.graph.observe.Observable#unregister(org.jboss.dna.graph.observe.ChangeObserver)
+ * @see
org.jboss.dna.graph.observe.Observable#unregister(org.jboss.dna.graph.observe.Observer)
*/
- public boolean unregister( ChangeObserver observer ) {
+ public boolean unregister( Observer observer ) {
return observationBus.unregister(observer);
}
@@ -212,7 +217,7 @@
// Close all connections to the pools. This is done inside the pools write lock.
try {
this.sourcesLock.readLock().lock();
- for (RepositoryConnectionPool pool : this.pools) {
+ for (RepositoryConnectionPool pool : this.pools.values()) {
pool.shutdown();
}
} finally {
@@ -236,7 +241,7 @@
// Check whether all source pools are shut down. This is done inside the pools
write lock.
try {
this.sourcesLock.readLock().lock();
- for (RepositoryConnectionPool pool : this.pools) {
+ for (RepositoryConnectionPool pool : this.pools.values()) {
if (!pool.awaitTermination(timeout, unit)) return false;
}
return true;
@@ -258,7 +263,7 @@
public boolean isTerminating() {
try {
this.sourcesLock.readLock().lock();
- for (RepositoryConnectionPool pool : this.pools) {
+ for (RepositoryConnectionPool pool : this.pools.values()) {
if (pool.isTerminating()) return true;
}
return false;
@@ -276,7 +281,7 @@
public boolean isTerminated() {
try {
this.sourcesLock.readLock().lock();
- for (RepositoryConnectionPool pool : this.pools) {
+ for (RepositoryConnectionPool pool : this.pools.values()) {
if (!pool.isTerminated()) return false;
}
return true;
@@ -291,11 +296,12 @@
* @return the pools
*/
public Collection<String> getSourceNames() {
- Set<String> sourceNames = new HashSet<String>();
- for (RepositoryConnectionPool pool : this.pools) {
- sourceNames.add(pool.getRepositorySource().getName());
+ try {
+ this.sourcesLock.readLock().lock();
+ return Collections.unmodifiableCollection(new
HashSet<String>(this.pools.keySet()));
+ } finally {
+ this.sourcesLock.readLock().unlock();
}
- return Collections.unmodifiableCollection(sourceNames);
}
/**
@@ -305,10 +311,15 @@
*/
public Collection<RepositorySource> getSources() {
List<RepositorySource> sources = new LinkedList<RepositorySource>();
- for (RepositoryConnectionPool pool : this.pools) {
- sources.add(pool.getRepositorySource());
+ try {
+ this.sourcesLock.readLock().lock();
+ for (RepositoryConnectionPool pool : this.pools.values()) {
+ sources.add(pool.getRepositorySource());
+ }
+ return Collections.unmodifiableCollection(sources);
+ } finally {
+ this.sourcesLock.readLock().unlock();
}
- return Collections.unmodifiableCollection(sources);
}
/**
@@ -320,14 +331,11 @@
public RepositorySource getSource( String sourceName ) {
try {
this.sourcesLock.readLock().lock();
- for (RepositoryConnectionPool existingPool : this.pools) {
- RepositorySource source = existingPool.getRepositorySource();
- if (source.getName().equals(sourceName)) return source;
- }
+ RepositoryConnectionPool existingPool = this.pools.get(sourceName);
+ return existingPool == null ? null : existingPool.getRepositorySource();
} finally {
this.sourcesLock.readLock().unlock();
}
- return null;
}
/**
@@ -339,14 +347,10 @@
public RepositoryConnectionPool getConnectionPool( String sourceName ) {
try {
this.sourcesLock.readLock().lock();
- for (RepositoryConnectionPool existingPool : this.pools) {
- RepositorySource source = existingPool.getRepositorySource();
- if (source.getName().equals(sourceName)) return existingPool;
- }
+ return this.pools.get(sourceName);
} finally {
this.sourcesLock.readLock().unlock();
}
- return null;
}
/**
@@ -357,68 +361,99 @@
* supplied name.
*/
public boolean addSource( RepositorySource source ) {
+ return addSource(source, false);
+ }
+
+ /**
+ * Add the supplied federated source. This method returns false if the source is
null.
+ * <p>
+ * If a source with the same name already exists, it will be replaced only if
<code>replaceIfExisting</code> is true. If this
+ * is the case, then the existing source will be removed from the connection pool,
and that pool will be
+ * {@link RepositoryConnectionPool#shutdown() shutdown} (allowing any in-use
connections to be used and finished normally).
+ * </p>
+ *
+ * @param source the source to add
+ * @param replaceIfExisting true if an existing source should be replaced, or false
if this method should return false if
+ * there is already an existing source with the supplied name.
+ * @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,
+ boolean replaceIfExisting ) {
if (source == null) return false;
- try {
- this.sourcesLock.writeLock().lock();
- final String sourceName = source.getName();
- for (RepositoryConnectionPool existingPool : this.pools) {
- if (existingPool.getRepositorySource().getName().equals(sourceName))
return false;
+ final String sourceName = source.getName();
+ if (!replaceIfExisting) {
+ // Don't want to replace existing, so make sure there isn't one
already ...
+ try {
+ this.sourcesLock.readLock().lock();
+ if (this.pools.containsKey(sourceName)) return false;
+ } finally {
+ this.sourcesLock.readLock().unlock();
}
- // Create a repository context for this source ...
- final ObservationBus observationBus = this.observationBus;
- RepositoryContext repositoryContext = new RepositoryContext() {
- /**
- * {@inheritDoc}
- *
- * @see
org.jboss.dna.graph.connector.RepositoryContext#getExecutionContext()
- */
- public ExecutionContext getExecutionContext() {
- return RepositoryLibrary.this.getExecutionContext();
- }
+ }
+ // Create a repository context for this source ...
+ final ObservationBus observationBus = this.observationBus;
+ RepositoryContext repositoryContext = new RepositoryContext() {
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.connector.RepositoryContext#getExecutionContext()
+ */
+ public ExecutionContext getExecutionContext() {
+ return RepositoryLibrary.this.getExecutionContext();
+ }
- /**
- * {@inheritDoc}
- *
- * @see
org.jboss.dna.graph.connector.RepositoryContext#getRepositoryConnectionFactory()
- */
- public RepositoryConnectionFactory getRepositoryConnectionFactory() {
- return RepositoryLibrary.this;
- }
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.connector.RepositoryContext#getRepositoryConnectionFactory()
+ */
+ public RepositoryConnectionFactory getRepositoryConnectionFactory() {
+ return RepositoryLibrary.this;
+ }
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.connector.RepositoryContext#getObserver()
- */
- public Observer getObserver() {
- return observationBus.hasObservers() ? observationBus : null;
- }
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.RepositoryContext#getObserver()
+ */
+ public Observer getObserver() {
+ return observationBus.hasObservers() ? observationBus : null;
+ }
- /**
- * {@inheritDoc}
- *
- * @see
org.jboss.dna.graph.connector.RepositoryContext#getConfiguration(int)
- */
- public Subgraph getConfiguration( int depth ) {
- Subgraph result = null;
- RepositorySource configSource = getConfigurationSource();
- if (configSource != null) {
- Graph config = Graph.create(configSource,
getExecutionContext());
- String workspaceName = getConfigurationWorkspaceName();
- if (workspaceName != null) {
- config.useWorkspace(workspaceName);
- }
- Path configPath = getPathToConfigurationRoot();
- Path sourcePath =
getExecutionContext().getValueFactories().getPathFactory().create(configPath,
-
sourceName);
- result = config.getSubgraphOfDepth(depth).at(sourcePath);
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.connector.RepositoryContext#getConfiguration(int)
+ */
+ public Subgraph getConfiguration( int depth ) {
+ Subgraph result = null;
+ RepositorySource configSource = getConfigurationSource();
+ if (configSource != null) {
+ Graph config = Graph.create(configSource, getExecutionContext());
+ String workspaceName = getConfigurationWorkspaceName();
+ if (workspaceName != null) {
+ config.useWorkspace(workspaceName);
}
- return result;
+ Path configPath = getPathToConfigurationRoot();
+ Path sourcePath =
getExecutionContext().getValueFactories().getPathFactory().create(configPath,
sourceName);
+ result = config.getSubgraphOfDepth(depth).at(sourcePath);
}
- };
- source.initialize(repositoryContext);
- RepositoryConnectionPool pool = new RepositoryConnectionPool(source);
- this.pools.add(pool);
+ return result;
+ }
+ };
+ // Do this before we remove the existing pool ...
+ source.initialize(repositoryContext);
+ RepositoryConnectionPool pool = new RepositoryConnectionPool(source);
+ try {
+ this.sourcesLock.writeLock().lock();
+ // Need to first remove any existing one ...
+ RepositoryConnectionPool existingPool = this.pools.remove(sourceName);
+ if (existingPool != null) {
+ // Then shut down the source gracefully (and don't wait) ...
+ existingPool.shutdown();
+ }
+ this.pools.put(sourceName, pool);
return true;
} finally {
this.sourcesLock.writeLock().unlock();
@@ -450,6 +485,32 @@
/**
* 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. However, this method never waits until the
connections are all closed, and is equivalent to
+ * calling <code>removeSource(name,0,TimeUnit.SECONDS)</code>.
+ *
+ * @param name the name of the source to be removed
+ * @return the source with the supplied name that was removed, or null if no existing
source matching the supplied name could
+ * be found
+ * @see #removeSource(String, long, TimeUnit)
+ */
+ public RepositorySource removeSource( String name ) {
+ try {
+ this.sourcesLock.writeLock().lock();
+ RepositoryConnectionPool existingPool = this.pools.remove(name);
+ if (existingPool != null) {
+ // Then shut down the source gracefully (and don't wait) ...
+ existingPool.shutdown();
+ return existingPool.getRepositorySource();
+ }
+ } finally {
+ this.sourcesLock.writeLock().unlock();
+ }
+ return 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.
*
* @param name the name of the source to be removed
@@ -459,18 +520,18 @@
* @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
+ * @see #removeSource(String)
*/
public RepositorySource removeSource( String name,
long timeToAwait,
TimeUnit unit ) throws InterruptedException {
try {
this.sourcesLock.writeLock().lock();
- for (RepositoryConnectionPool existingPool : this.pools) {
- if (existingPool.getRepositorySource().getName().equals(name)) {
- // Shut down the source ...
- existingPool.shutdown();
- if (timeToAwait > 0L) existingPool.awaitTermination(timeToAwait,
unit);
- }
+ RepositoryConnectionPool existingPool = this.pools.remove(name);
+ if (existingPool != null) {
+ // Then shut down the source gracefully (and don't wait) ...
+ existingPool.shutdown();
+ if (timeToAwait > 0L) existingPool.awaitTermination(timeToAwait,
unit);
return existingPool.getRepositorySource();
}
} finally {
@@ -487,10 +548,8 @@
public RepositoryConnection createConnection( String sourceName ) {
try {
this.sourcesLock.readLock().lock();
- for (RepositoryConnectionPool existingPool : this.pools) {
- RepositorySource source = existingPool.getRepositorySource();
- if (source.getName().equals(sourceName)) return
existingPool.getConnection();
- }
+ RepositoryConnectionPool existingPool = this.pools.get(sourceName);
+ if (existingPool != null) return existingPool.getConnection();
RepositoryConnectionFactory delegate = this.delegate;
if (delegate != null) {
return delegate.createConnection(sourceName);
@@ -500,65 +559,4 @@
}
return null;
}
-
- protected interface ObservationBus extends Observable, Observer {
- boolean hasObservers();
-
- void shutdown();
- }
-
- protected class InMemoryObservationBus implements ObservationBus {
- private final ChangeObservers observers = new ChangeObservers();
-
- protected InMemoryObservationBus() {
- }
-
- /**
- * {@inheritDoc}
- *
- * @see
org.jboss.dna.graph.observe.Observable#register(org.jboss.dna.graph.observe.ChangeObserver)
- */
- public boolean register( ChangeObserver observer ) {
- return observers.register(observer);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see
org.jboss.dna.graph.observe.Observable#unregister(org.jboss.dna.graph.observe.ChangeObserver)
- */
- public boolean unregister( ChangeObserver observer ) {
- return observers.unregister(observer);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see
org.jboss.dna.graph.observe.Observer#notify(org.jboss.dna.graph.observe.Changes)
- */
- public void notify( Changes changes ) {
- if (changes != null) {
- // Broadcast the changes to the registered observers ...
- observers.broadcast(changes);
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.RepositoryLibrary.ObservationBus#hasObservers()
- */
- public boolean hasObservers() {
- return !observers.isEmpty();
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.repository.RepositoryLibrary.ObservationBus#shutdown()
- */
- public void shutdown() {
- observers.shutdown();
- }
- }
}
Modified:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
===================================================================
---
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java 2009-08-25
15:04:41 UTC (rev 1173)
+++
trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java 2009-08-26
18:10:37 UTC (rev 1174)
@@ -42,6 +42,9 @@
import org.jboss.dna.graph.Node;
import org.jboss.dna.graph.Subgraph;
import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.observe.Changes;
+import org.jboss.dna.graph.observe.NetChangeObserver;
+import org.jboss.dna.graph.observe.Observer;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
@@ -58,7 +61,7 @@
* @author Randall Hauch
*/
@ThreadSafe
-public class RepositoryService implements AdministeredService {
+public class RepositoryService implements AdministeredService, Observer {
/**
* The administrative component for this service.
@@ -104,6 +107,7 @@
private final String configurationSourceName;
private final String configurationWorkspaceName;
private final Path pathToConfigurationRoot;
+ private final ConfigurationChangeObserver configurationChangeObserver;
private final Administrator administrator = new Administrator();
private final AtomicBoolean started = new AtomicBoolean(false);
/** The problem sink used when encountering problems while starting repositories */
@@ -141,26 +145,27 @@
this.configurationWorkspaceName = configurationWorkspaceName;
this.context = context;
this.problems = problems;
+ this.configurationChangeObserver = new ConfigurationChangeObserver();
}
/**
* {@inheritDoc}
*/
- public ServiceAdministrator getAdministrator() {
+ public final ServiceAdministrator getAdministrator() {
return this.administrator;
}
/**
* @return configurationSourceName
*/
- public String getConfigurationSourceName() {
+ public final String getConfigurationSourceName() {
return configurationSourceName;
}
/**
* @return configurationWorkspaceName
*/
- public String getConfigurationWorkspaceName() {
+ public final String getConfigurationWorkspaceName() {
return configurationWorkspaceName;
}
@@ -169,14 +174,21 @@
*
* @return the RepositorySource library; never null
*/
- public RepositoryLibrary getRepositoryLibrary() {
+ public final RepositoryLibrary getRepositoryLibrary() {
return sources;
}
/**
+ * @return pathToConfigurationRoot
+ */
+ protected final Path getPathToConfigurationRoot() {
+ return pathToConfigurationRoot;
+ }
+
+ /**
* @return env
*/
- public ExecutionContext getExecutionEnvironment() {
+ public final ExecutionContext getExecutionEnvironment() {
return context;
}
@@ -186,7 +198,7 @@
}
protected synchronized void startService() {
- if (this.started.get() == false) {
+ if (this.started.get() == false) {
//
------------------------------------------------------------------------------------
// Read the configuration ...
//
------------------------------------------------------------------------------------
@@ -211,7 +223,7 @@
} catch (Throwable err) {
throw new
FederationException(RepositoryI18n.errorStartingRepositoryService.text(), err);
}
-
+
this.started.set(true);
}
}
@@ -404,4 +416,58 @@
if (obj == this) return true;
return false;
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.observe.Observer#notify(org.jboss.dna.graph.observe.Changes)
+ */
+ public void notify( Changes changes ) {
+ // Forward the changes to the net change observer ...
+ this.configurationChangeObserver.notify(changes);
+ }
+
+ protected class ConfigurationChangeObserver extends NetChangeObserver {
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.observe.NetChangeObserver#notify(org.jboss.dna.graph.observe.NetChangeObserver.NetChange)
+ */
+ @Override
+ protected void notify( NetChange change ) {
+ if (!getConfigurationSourceName().equals(change.getRepositorySourceName()))
return;
+ if
(!getConfigurationWorkspaceName().equals(change.getRepositoryWorkspaceName())) return;
+ Path changedPath = change.getPath();
+ Path configPath = getPathToConfigurationRoot();
+ if (!changedPath.isAtOrBelow(getPathToConfigurationRoot())) return;
+ boolean changedNodeIsPotentiallySource = configPath.size() + 1 ==
changedPath.size();
+
+ // At this point, we know that something inside the configuration changed, so
figure out what happened ...
+ if (changedNodeIsPotentiallySource &&
change.includes(ChangeType.NODE_REMOVED)) {
+ // Then potentially a source with the supplied name has been removed ...
+ String sourceName =
changedPath.getLastSegment().getName().getLocalName();
+ getRepositoryLibrary().removeSource(sourceName);
+ } else {
+ // The add/change/remove is either at or below a source, so try to create
a new source for it ...
+ Path sourcePath = changedNodeIsPotentiallySource ? changedPath :
changedPath.subpath(0, configPath.size() + 1);
+ Problems problems = new SimpleProblems();
+ // Now read the node and create the source ...
+ Graph graph = Graph.create(getConfigurationSourceName(),
getRepositoryLibrary(), getExecutionEnvironment());
+ try {
+ String workspaceName = getConfigurationWorkspaceName();
+ if (workspaceName != null) graph.useWorkspace(workspaceName);
+ Map<Name, Property> properties =
graph.getPropertiesByName().on(sourcePath);
+ RepositorySource source = createRepositorySource(sourcePath,
properties, problems);
+ if (source != null) {
+ // It was the config for a source, so try to add or replace an
existing source ...
+ getRepositoryLibrary().addSource(source, true);
+ }
+ } catch (PathNotFoundException e) {
+ // No source was found, and this is okay (since it may just been
deleted)...
+ String sourceName =
changedPath.getLastSegment().getName().getLocalName();
+ getRepositoryLibrary().removeSource(sourceName);
+ }
+ }
+ }
+ }
}
Added:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/SimpleRepositoryContext.java
===================================================================
---
trunk/dna-repository/src/main/java/org/jboss/dna/repository/SimpleRepositoryContext.java
(rev 0)
+++
trunk/dna-repository/src/main/java/org/jboss/dna/repository/SimpleRepositoryContext.java 2009-08-26
18:10:37 UTC (rev 1174)
@@ -0,0 +1,88 @@
+/*
+ * JBoss DNA (
http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you 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.
+ *
+ * JBoss DNA 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;
+
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Subgraph;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+import org.jboss.dna.graph.connector.RepositoryContext;
+import org.jboss.dna.graph.observe.Observer;
+
+/**
+ * A simple, immutable {@link RepositoryContext} implementation that uses the references
supplied as parameters to the
+ * constructor.
+ */
+@Immutable
+public class SimpleRepositoryContext implements RepositoryContext {
+
+ private final ExecutionContext context;
+ private final Observer observer;
+ private final RepositoryConnectionFactory connectionFactory;
+
+ public SimpleRepositoryContext( ExecutionContext context,
+ Observer observer,
+ RepositoryConnectionFactory connectionFactory ) {
+ this.context = context;
+ this.observer = observer;
+ this.connectionFactory = connectionFactory;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.RepositoryContext#getConfiguration(int)
+ */
+ public Subgraph getConfiguration( int depth ) {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.RepositoryContext#getExecutionContext()
+ */
+ public ExecutionContext getExecutionContext() {
+ return context;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.connector.RepositoryContext#getObserver()
+ */
+ public Observer getObserver() {
+ return observer;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.connector.RepositoryContext#getRepositoryConnectionFactory()
+ */
+ public RepositoryConnectionFactory getRepositoryConnectionFactory() {
+ return connectionFactory;
+ }
+
+}
Property changes on:
trunk/dna-repository/src/main/java/org/jboss/dna/repository/SimpleRepositoryContext.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF