[dna-commits] DNA SVN: r572 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/commands and 30 other directories.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Thu Oct 23 14:46:32 EDT 2008


Author: rhauch
Date: 2008-10-23 14:46:32 -0400 (Thu, 23 Oct 2008)
New Revision: 572

Added:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/NodeConflictBehavior.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CacheableRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/processor/
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/processor/LoggingRequestProcessor.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/processor/RequestProcessor.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
Removed:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/commands/basic/
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/commands/executor/
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RequestProcessor.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/commands/executor/
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommand.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommand.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommand.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCreateNodeCommand.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommand.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommand.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommand.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommand.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommand.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommand.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommand.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommandTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommandTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommandTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommandTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommandTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommandTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommandTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommandTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommandTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommandTest.java
Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/Node.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/Subgraph.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/RepositoryConnection.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/RepositoryConnectionPool.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/PathNotFoundException.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPath.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CompositeRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CopyBranchRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CreateNodeRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/DeleteBranchRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/MoveBranchRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadAllChildrenRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadAllPropertiesRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadBlockOfChildrenRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadBranchRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadNodeRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadPropertyRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RemovePropertiesRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RenameNodeRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/Request.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/UpdatePropertiesRequest.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/util/GraphImporter.java
   trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/RepositorySourceLoadHarness.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/SimpleRepository.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/SimpleRepositorySource.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/TimeDelayingRepositorySource.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/util/GraphImporterTest.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
   trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java
   trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepository.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConnection.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiChildContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NodeContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NonEmptyContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OneChildContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OnePropertyContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PlaceholderContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoChildContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContribution.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FederatedNode.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java
   trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java
   trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryConnectionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutorTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java
   trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java
   trunk/extensions/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java
   trunk/extensions/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java
   trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java
   trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectionTest.java
Log:
DNA-213 - Review the graph SPI commands to add missing commands and better handle node identification (e.g., when getting children)
http://jira.jboss.com/jira/browse/DNA-213

Finished the conversion from the old GraphCommand classes to the newer Request classes.  This involved a very large number of changes, some of which changed from using commands to using the new Graph API.  The new Request classes do a much better job of recording identification properties of the nodes added as results to the requests.

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -21,6 +21,9 @@
  */
 package org.jboss.dna.graph;
 
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -33,6 +36,7 @@
 import net.jcip.annotations.Immutable;
 import net.jcip.annotations.NotThreadSafe;
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.cache.CachePolicy;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
 import org.jboss.dna.graph.connectors.RepositorySource;
@@ -42,6 +46,7 @@
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
 import org.jboss.dna.graph.properties.PropertyFactory;
+import org.jboss.dna.graph.properties.Path.Segment;
 import org.jboss.dna.graph.requests.CompositeRequest;
 import org.jboss.dna.graph.requests.CopyBranchRequest;
 import org.jboss.dna.graph.requests.CreateNodeRequest;
@@ -53,7 +58,10 @@
 import org.jboss.dna.graph.requests.ReadBranchRequest;
 import org.jboss.dna.graph.requests.ReadNodeRequest;
 import org.jboss.dna.graph.requests.ReadPropertyRequest;
+import org.jboss.dna.graph.requests.RemovePropertiesRequest;
 import org.jboss.dna.graph.requests.Request;
+import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
+import org.jboss.dna.graph.util.GraphImporter;
 
 /**
  * A graph representation of the content within a {@link RepositorySource}, including mechanisms to interact and manipulate that
@@ -138,6 +146,25 @@
     }
 
     /**
+     * Get the default cache policy for this graph. May be null if such a policy has not been defined for thie
+     * {@link #getSourceName() source}.
+     * 
+     * @return the default cache policy, or null if no such policy has been defined for the source
+     * @throws RepositorySourceException if no repository source with the {@link #getSourceName() name} could be found
+     */
+    public CachePolicy getDefaultCachePolicy() {
+        RepositoryConnection connection = this.connectionFactory.createConnection(getSourceName());
+        if (connection == null) {
+            throw new RepositorySourceException(GraphI18n.unableToFindRepositorySourceWithName.text(getSourceName()));
+        }
+        try {
+            return connection.getDefaultCachePolicy();
+        } finally {
+            connection.close();
+        }
+    }
+
+    /**
      * Begin the request to move the specified node into a parent node at a different location, which is specified via the
      * <code>into(...)</code> method on the returned {@link Move} object.
      * <p>
@@ -455,8 +482,7 @@
      * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
      * 
      * @param atPath the path to the node that is to be created.
-     * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
-     *         node where the node is to be created
+     * @return an object that may be used to start another request
      */
     public Conjunction<Graph> create( String atPath ) {
         this.requestQueue.submit(new CreateNodeRequest(new Location(createPath(atPath))));
@@ -468,8 +494,7 @@
      * 
      * @param atPath the path to the node that is to be created.
      * @param properties the properties for the new node
-     * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
-     *         node where the node is to be created
+     * @return an object that may be used to start another request
      */
     public Conjunction<Graph> create( String atPath,
                                       Property... properties ) {
@@ -481,8 +506,7 @@
      * Begin the request to create a node located at the supplied path. This request is submitted to the repository immediately.
      * 
      * @param at the path to the node that is to be created.
-     * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
-     *         node where the node is to be created
+     * @return an object that may be used to start another request
      */
     public Conjunction<Graph> create( Path at ) {
         this.requestQueue.submit(new CreateNodeRequest(new Location(at)));
@@ -494,8 +518,7 @@
      * 
      * @param at the path to the node that is to be created.
      * @param properties the properties for the new node
-     * @return the object that can be used to specify addition properties for the new node to be copied or the location of the
-     *         node where the node is to be created
+     * @return an object that may be used to start another request
      */
     public Conjunction<Graph> create( Path at,
                                       Property... properties ) {
@@ -504,6 +527,125 @@
     }
 
     /**
+     * Set the properties on a node.
+     * 
+     * @param properties the properties to set
+     * @return the remove request object that should be used to specify the node on which the properties are to be set.
+     */
+    public On<Conjunction<Graph>> set( final Property... properties ) {
+        return new On<Conjunction<Graph>>() {
+            @SuppressWarnings( "synthetic-access" )
+            public Conjunction<Graph> on( Location location ) {
+                UpdatePropertiesRequest request = new UpdatePropertiesRequest(location, properties);
+                queue().submit(request);
+                return nextGraph;
+            }
+
+            public Conjunction<Graph> on( String path ) {
+                return on(new Location(createPath(path)));
+            }
+
+            public Conjunction<Graph> on( Path path ) {
+                return on(new Location(path));
+            }
+
+            public Conjunction<Graph> on( Property idProperty ) {
+                return on(new Location(idProperty));
+            }
+
+            public Conjunction<Graph> on( Property firstIdProperty,
+                                          Property... additionalIdProperties ) {
+                return on(new Location(firstIdProperty, additionalIdProperties));
+            }
+
+            public Conjunction<Graph> on( UUID uuid ) {
+                return on(new Location(uuid));
+            }
+        };
+    }
+
+    /**
+     * Remove properties from the node at the given location.
+     * 
+     * @param propertyNames the names of the properties to be removed
+     * @return the remove request object that should be used to specify the node from which the properties are to be removed.
+     */
+    public On<Conjunction<Graph>> remove( final Name... propertyNames ) {
+        return new On<Conjunction<Graph>>() {
+            @SuppressWarnings( "synthetic-access" )
+            public Conjunction<Graph> on( Location location ) {
+                RemovePropertiesRequest request = new RemovePropertiesRequest(location, propertyNames);
+                queue().submit(request);
+                return nextGraph;
+            }
+
+            public Conjunction<Graph> on( String path ) {
+                return on(new Location(createPath(path)));
+            }
+
+            public Conjunction<Graph> on( Path path ) {
+                return on(new Location(path));
+            }
+
+            public Conjunction<Graph> on( Property idProperty ) {
+                return on(new Location(idProperty));
+            }
+
+            public Conjunction<Graph> on( Property firstIdProperty,
+                                          Property... additionalIdProperties ) {
+                return on(new Location(firstIdProperty, additionalIdProperties));
+            }
+
+            public Conjunction<Graph> on( UUID uuid ) {
+                return on(new Location(uuid));
+            }
+        };
+    }
+
+    /**
+     * Remove properties from the node at the given location.
+     * 
+     * @param propertyNames the names of the properties to be removed
+     * @return the remove request object that should be used to specify the node from which the properties are to be removed.
+     */
+    public On<Conjunction<Graph>> remove( String... propertyNames ) {
+        NameFactory nameFactory = getContext().getValueFactories().getNameFactory();
+        final List<Name> names = new LinkedList<Name>();
+        for (String propertyName : propertyNames) {
+            names.add(nameFactory.create(propertyName));
+        }
+        return new On<Conjunction<Graph>>() {
+            @SuppressWarnings( "synthetic-access" )
+            public Conjunction<Graph> on( Location location ) {
+                RemovePropertiesRequest request = new RemovePropertiesRequest(location, names);
+                queue().submit(request);
+                return nextGraph;
+            }
+
+            public Conjunction<Graph> on( String path ) {
+                return on(new Location(createPath(path)));
+            }
+
+            public Conjunction<Graph> on( Path path ) {
+                return on(new Location(path));
+            }
+
+            public Conjunction<Graph> on( Property idProperty ) {
+                return on(new Location(idProperty));
+            }
+
+            public Conjunction<Graph> on( Property firstIdProperty,
+                                          Property... additionalIdProperties ) {
+                return on(new Location(firstIdProperty, additionalIdProperties));
+            }
+
+            public Conjunction<Graph> on( UUID uuid ) {
+                return on(new Location(uuid));
+            }
+        };
+    }
+
+    /**
      * Request that the properties be read on the node defined via the <code>on(...)</code> method on the returned {@link On}
      * object. Once the location is specified, the {@link Collection collection of properties} are read and then returned.
      * 
@@ -828,12 +970,81 @@
         };
     }
 
+    /**
+     * Import the content from the XML file at the supplied URI, specifying via the returned {@link ImportInto object} where the
+     * content is to be imported.
+     * 
+     * @param uri the URI where the importer can read the content that is to be imported
+     * @return the object that should be used to specify into which the content is to be imported
+     * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
+     */
+    public ImportInto<Conjunction<Graph>> importXmlFrom( final URI uri ) {
+        return new ImportInto<Conjunction<Graph>>() {
+            public Conjunction<Graph> into( String path ) throws IOException {
+                return into(new Location(createPath(path)));
+            }
+
+            public Conjunction<Graph> into( Path path ) throws IOException {
+                return into(new Location(path));
+            }
+
+            public Conjunction<Graph> into( Property idProperty ) throws IOException {
+                return into(new Location(idProperty));
+            }
+
+            public Conjunction<Graph> into( Property firstIdProperty,
+                                            Property... additionalIdProperties ) throws IOException {
+                return into(new Location(firstIdProperty, additionalIdProperties));
+            }
+
+            public Conjunction<Graph> into( UUID uuid ) throws IOException {
+                return into(new Location(uuid));
+            }
+
+            @SuppressWarnings( "synthetic-access" )
+            public Conjunction<Graph> into( Location at ) throws IOException {
+                GraphImporter importer = new GraphImporter(Graph.this);
+                importer.importXml(uri, at).execute(); // 'importXml' creates and uses a new batch
+                return Graph.this.nextGraph;
+            }
+        };
+    }
+
+    /**
+     * Import the content from the XML file at the supplied file location, specifying via the returned {@link ImportInto object}
+     * where the content is to be imported.
+     * 
+     * @param pathToFile the path to the XML file that should be imported.
+     * @return the object that should be used to specify into which the content is to be imported
+     * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
+     */
+    public ImportInto<Conjunction<Graph>> importXmlFrom( String pathToFile ) {
+        CheckArg.isNotNull(pathToFile, "pathToFile");
+        return importXmlFrom(new File(pathToFile).toURI());
+    }
+
+    /**
+     * Import the content from the XML file at the supplied file, specifying via the returned {@link ImportInto object} where the
+     * content is to be imported.
+     * 
+     * @param file the XML file that should be imported.
+     * @return the object that should be used to specify into which the content is to be imported
+     * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
+     */
+    public ImportInto<Conjunction<Graph>> importXmlFrom( File file ) {
+        CheckArg.isNotNull(file, "file");
+        return importXmlFrom(file.toURI());
+    }
+
     /*package*/Path createPath( String path ) {
         return getContext().getValueFactories().getPathFactory().create(path);
     }
 
     /*package*/void execute( Request request ) {
-        RepositoryConnection connection = Graph.this.getConnectionFactory().createConnection(Graph.this.getSourceName());
+        RepositoryConnection connection = Graph.this.getConnectionFactory().createConnection(getSourceName());
+        if (connection == null) {
+            throw new RepositorySourceException(GraphI18n.unableToFindRepositorySourceWithName.text(getSourceName()));
+        }
         try {
             connection.execute(Graph.this.getContext(), request);
         } finally {
@@ -846,6 +1057,14 @@
         }
     }
 
+    /*package*/List<Segment> getSegments( List<Location> locations ) {
+        List<Segment> segments = new ArrayList<Segment>(locations.size());
+        for (Location location : locations) {
+            segments.add(location.getPath().getLastSegment());
+        }
+        return segments;
+    }
+
     /**
      * Begin a batch of requests to perform various operations. Use this approach when multiple operations are to be built and
      * then executed with one submission to the underlying {@link #getSourceName() repository source}. The {@link Results results}
@@ -1365,6 +1584,122 @@
         }
 
         /**
+         * Set the properties on a node.
+         * 
+         * @param properties the properties to set
+         * @return the remove request object that should be used to specify the node on which the properties are to be set.
+         */
+        public On<BatchConjunction> set( final Property... properties ) {
+            return new On<BatchConjunction>() {
+                public BatchConjunction on( Location location ) {
+                    UpdatePropertiesRequest request = new UpdatePropertiesRequest(location, properties);
+                    queue().submit(request);
+                    return nextRequests;
+                }
+
+                public BatchConjunction on( String path ) {
+                    return on(new Location(createPath(path)));
+                }
+
+                public BatchConjunction on( Path path ) {
+                    return on(new Location(path));
+                }
+
+                public BatchConjunction on( Property idProperty ) {
+                    return on(new Location(idProperty));
+                }
+
+                public BatchConjunction on( Property firstIdProperty,
+                                            Property... additionalIdProperties ) {
+                    return on(new Location(firstIdProperty, additionalIdProperties));
+                }
+
+                public BatchConjunction on( UUID uuid ) {
+                    return on(new Location(uuid));
+                }
+            };
+        }
+
+        /**
+         * Remove properties from the node at the given location.
+         * 
+         * @param propertyNames the names of the properties to be removed
+         * @return the remove request object that should be used to specify the node from which the properties are to be removed.
+         */
+        public On<BatchConjunction> remove( final Name... propertyNames ) {
+            return new On<BatchConjunction>() {
+                public BatchConjunction on( Location location ) {
+                    RemovePropertiesRequest request = new RemovePropertiesRequest(location, propertyNames);
+                    queue().submit(request);
+                    return nextRequests;
+                }
+
+                public BatchConjunction on( String path ) {
+                    return on(new Location(createPath(path)));
+                }
+
+                public BatchConjunction on( Path path ) {
+                    return on(new Location(path));
+                }
+
+                public BatchConjunction on( Property idProperty ) {
+                    return on(new Location(idProperty));
+                }
+
+                public BatchConjunction on( Property firstIdProperty,
+                                            Property... additionalIdProperties ) {
+                    return on(new Location(firstIdProperty, additionalIdProperties));
+                }
+
+                public BatchConjunction on( UUID uuid ) {
+                    return on(new Location(uuid));
+                }
+            };
+        }
+
+        /**
+         * Remove properties from the node at the given location.
+         * 
+         * @param propertyNames the names of the properties to be removed
+         * @return the remove request object that should be used to specify the node from which the properties are to be removed.
+         */
+        public On<BatchConjunction> remove( String... propertyNames ) {
+            NameFactory nameFactory = getContext().getValueFactories().getNameFactory();
+            final List<Name> names = new LinkedList<Name>();
+            for (String propertyName : propertyNames) {
+                names.add(nameFactory.create(propertyName));
+            }
+            return new On<BatchConjunction>() {
+                public BatchConjunction on( Location location ) {
+                    RemovePropertiesRequest request = new RemovePropertiesRequest(location, names);
+                    queue().submit(request);
+                    return nextRequests;
+                }
+
+                public BatchConjunction on( String path ) {
+                    return on(new Location(createPath(path)));
+                }
+
+                public BatchConjunction on( Path path ) {
+                    return on(new Location(path));
+                }
+
+                public BatchConjunction on( Property idProperty ) {
+                    return on(new Location(idProperty));
+                }
+
+                public BatchConjunction on( Property firstIdProperty,
+                                            Property... additionalIdProperties ) {
+                    return on(new Location(firstIdProperty, additionalIdProperties));
+                }
+
+                public BatchConjunction on( UUID uuid ) {
+                    return on(new Location(uuid));
+                }
+            };
+        }
+
+        /**
          * Request to read the node with the supplied UUID.
          * <p>
          * Like all other methods on the {@link Batch}, the request will be performed when the {@link #execute()} method is
@@ -2094,6 +2429,72 @@
                  Property... additionalIdProperties );
     }
 
+    /**
+     * A component that defines the location into which a node should be copied or moved.
+     * 
+     * @param <Next> The interface that is to be returned when this request is completed
+     * @author Randall Hauch
+     */
+    public interface ImportInto<Next> {
+        /**
+         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * 
+         * @param to the location of the new parent
+         * @return the interface for additional requests or actions
+         * @throws IOException if there is a problem reading the content being imported
+         */
+        Next into( Location to ) throws IOException;
+
+        /**
+         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * 
+         * @param toPath the path of the new parent
+         * @return the interface for additional requests or actions
+         * @throws IOException if there is a problem reading the content being imported
+         */
+        Next into( String toPath ) throws IOException;
+
+        /**
+         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * 
+         * @param to the path of the new parent
+         * @return the interface for additional requests or actions
+         * @throws IOException if there is a problem reading the content being imported
+         */
+        Next into( Path to ) throws IOException;
+
+        /**
+         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * 
+         * @param to the UUID of the new parent
+         * @return the interface for additional requests or actions
+         * @throws IOException if there is a problem reading the content being imported
+         */
+        Next into( UUID to ) throws IOException;
+
+        /**
+         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * 
+         * @param idProperty the property that uniquely identifies the new parent
+         * @return the interface for additional requests or actions
+         * @throws IOException if there is a problem reading the content being imported
+         */
+        Next into( Property idProperty ) throws IOException;
+
+        /**
+         * Finish the import by specifying the new location into which the node should be copied/moved.
+         * 
+         * @param firstIdProperty the first property that, with the <code>additionalIdProperties</code>, uniquely identifies the
+         *        new parent
+         * @param additionalIdProperties the additional properties that, with the <code>additionalIdProperties</code>, uniquely
+         *        identifies the new parent
+         * @return the interface for additional requests or actions
+         * @throws IOException if there is a problem reading the content being imported
+         */
+        Next into( Property firstIdProperty,
+                   Property... additionalIdProperties ) throws IOException;
+    }
+
     public interface BatchConjunction extends Conjunction<Batch>, Executable {
     }
 
@@ -2189,7 +2590,7 @@
         }
 
         public Location getLocation() {
-            return request.at();
+            return request.getActualLocationOfNode();
         }
 
         public Graph getGraph() {
@@ -2200,6 +2601,15 @@
             return request.getProperties();
         }
 
+        public Property getProperty( Name name ) {
+            return getPropertiesByName().get(name);
+        }
+
+        public Property getProperty( String nameStr ) {
+            Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
+            return getPropertiesByName().get(name);
+        }
+
         public Map<Name, Property> getPropertiesByName() {
             return request.getPropertiesByName();
         }
@@ -2212,6 +2622,10 @@
             return request.getChildren().size() > 0;
         }
 
+        public List<Segment> getChildrenSegments() {
+            return getSegments(getChildren());
+        }
+
         public Iterator<Location> iterator() {
             return request.getChildren().iterator();
         }
@@ -2247,20 +2661,20 @@
             for (Request request : requests) {
                 if (request instanceof ReadAllPropertiesRequest) {
                     ReadAllPropertiesRequest read = (ReadAllPropertiesRequest)request;
-                    getOrCreateNode(read.at()).setProperties(read.getPropertiesByName());
+                    getOrCreateNode(read.getActualLocationOfNode()).setProperties(read.getPropertiesByName());
                 } else if (request instanceof ReadPropertyRequest) {
                     ReadPropertyRequest read = (ReadPropertyRequest)request;
-                    getOrCreateNode(read.on()).addProperty(read.getProperty());
+                    getOrCreateNode(read.getActualLocationOfNode()).addProperty(read.getProperty());
                 } else if (request instanceof ReadNodeRequest) {
                     ReadNodeRequest read = (ReadNodeRequest)request;
-                    BatchResultsNode node = getOrCreateNode(read.at());
+                    BatchResultsNode node = getOrCreateNode(read.getActualLocationOfNode());
                     node.setProperties(read.getPropertiesByName());
                     node.setChildren(read.getChildren());
                 } else if (request instanceof ReadBlockOfChildrenRequest) {
                     throw new IllegalStateException();
                 } else if (request instanceof ReadAllChildrenRequest) {
                     ReadAllChildrenRequest read = (ReadAllChildrenRequest)request;
-                    getOrCreateNode(read.of()).setChildren(read.getChildren());
+                    getOrCreateNode(read.getActualLocationOfNode()).setChildren(read.getChildren());
                 } else if (request instanceof ReadBranchRequest) {
                     ReadBranchRequest read = (ReadBranchRequest)request;
                     for (Location location : read) {
@@ -2376,6 +2790,10 @@
             else children = Collections.emptyList();
         }
 
+        public List<Segment> getChildrenSegments() {
+            return getSegments(getChildren());
+        }
+
         public Graph getGraph() {
             return Graph.this;
         }
@@ -2392,6 +2810,15 @@
             return properties;
         }
 
+        public Property getProperty( Name name ) {
+            return properties.get(name);
+        }
+
+        public Property getProperty( String nameStr ) {
+            Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
+            return properties.get(name);
+        }
+
         public List<Location> getChildren() {
             return children;
         }
@@ -2441,9 +2868,13 @@
         }
 
         public Location getLocation() {
-            return request.at();
+            return request.getActualLocationOfNode();
         }
 
+        public Node getRoot() {
+            return getNode(getLocation());
+        }
+
         public int getMaximumDepth() {
             return request.maximumDepth();
         }
@@ -2468,7 +2899,7 @@
         public boolean includes( Path path ) {
             CheckArg.isNotNull(path, "path");
             path = getAbsolutePath(path);
-            return includes(new Location(path));
+            return request.includes(path);
         }
 
         public boolean includes( Location location ) {
@@ -2479,30 +2910,35 @@
         public boolean includes( String pathStr ) {
             Path path = createPath(pathStr);
             path = getAbsolutePath(path);
-            return includes(new Location(path));
+            return includes(path);
         }
 
         public Node getNode( Location location ) {
-            if (!includes(location)) return null;
-            return new SubgraphNode(location, request);
+            if (!location.hasPath()) return null;
+            Location actualLocation = request.getLocationFor(location.getPath());
+            if (actualLocation == null) return null;
+            return new SubgraphNode(actualLocation, request);
         }
 
         public Node getNode( Path path ) {
             path = getAbsolutePath(path);
-            return getNode(new Location(path));
+            if (!includes(path)) return null;
+            Location location = request.getLocationFor(path);
+            if (location == null) return null;
+            return new SubgraphNode(location, request);
         }
 
         public Node getNode( String pathStr ) {
             CheckArg.isNotEmpty(pathStr, "path");
             Path path = createPath(pathStr);
             path = getAbsolutePath(path);
-            return getNode(new Location(path));
+            return getNode(path);
         }
 
         protected Path getAbsolutePath( Path absoluteOrRelative ) {
             Path result = absoluteOrRelative;
             if (!result.isAbsolute()) {
-                result = getGraph().getContext().getValueFactories().getPathFactory().create(request.at().getPath(), result);
+                result = getGraph().getContext().getValueFactories().getPathFactory().create(getLocation().getPath(), result);
                 result = result.getNormalizedPath();
             }
             return result;
@@ -2550,12 +2986,25 @@
             return request.getPropertiesFor(location);
         }
 
+        public Property getProperty( Name name ) {
+            return getPropertiesByName().get(name);
+        }
+
+        public Property getProperty( String nameStr ) {
+            Name name = getContext().getValueFactories().getNameFactory().create(nameStr);
+            return getPropertiesByName().get(name);
+        }
+
         public boolean hasChildren() {
             return getChildren().size() != 0;
         }
 
+        public List<Segment> getChildrenSegments() {
+            return getSegments(getChildren());
+        }
+
         public Iterator<Location> iterator() {
-            return request.iterator();
+            return getChildren().iterator();
         }
 
         @Override

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -60,12 +60,20 @@
     public static I18n pathExpressionHasInvalidMatch;
     public static I18n messageDigestNotFound;
 
-    public static I18n executingGraphCommand;
-    public static I18n executedGraphCommand;
-    public static I18n closingCommandExecutor;
-    public static I18n closedCommandExecutor;
+    public static I18n executingRequest;
+    public static I18n executedRequest;
+    public static I18n closingRequestProcessor;
+    public static I18n closedRequestProcessor;
     public static I18n multipleErrorsWhileExecutingRequests;
     public static I18n unableToAddMoreRequestsToAlreadyExecutedBatch;
+    public static I18n actualLocationIsNotSameAsInputLocation;
+    public static I18n actualLocationMustHavePath;
+    public static I18n actualNewLocationIsNotSameAsInputLocation;
+    public static I18n actualNewLocationMustHavePath;
+    public static I18n actualOldLocationIsNotSameAsInputLocation;
+    public static I18n actualOldLocationMustHavePath;
+    public static I18n actualNewLocationMustHaveSameParentAsOldLocation;
+    public static I18n actualNewLocationMustHaveSameNameAsRequest;
 
     // XML Sequencer
     public static I18n errorSequencingXmlDocument;

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Location.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -23,12 +23,15 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
+import java.util.NoSuchElementException;
 import java.util.UUID;
 import net.jcip.annotations.Immutable;
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.common.util.HashCode;
 import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
 import org.jboss.dna.graph.properties.basic.BasicSingleValueProperty;
@@ -39,8 +42,22 @@
  * @author Randall Hauch
  */
 @Immutable
-public class Location {
+public class Location implements Iterable<Property> {
 
+    private static final Iterator<Property> NO_ID_PROPERTIES_ITERATOR = new Iterator<Property>() {
+        public boolean hasNext() {
+            return false;
+        }
+
+        public Property next() {
+            throw new NoSuchElementException();
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    };
+
     private final Path path;
     private final List<Property> idProperties;
 
@@ -73,16 +90,19 @@
      * Create a location defined by a path and an UUID.
      * 
      * @param path the path
-     * @param uuid the UUID
-     * @throws IllegalArgumentException if <code>uuid</code> is null
+     * @param uuid the UUID, or null if there is no UUID
+     * @throws IllegalArgumentException if <code>path</code> is null
      */
     public Location( Path path,
                      UUID uuid ) {
         CheckArg.isNotNull(uuid, "uuid");
-        CheckArg.isNotNull(path, "path");
         this.path = path;
-        Property idProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
-        this.idProperties = Collections.singletonList(idProperty);
+        if (uuid != null) {
+            Property idProperty = new BasicSingleValueProperty(DnaLexicon.UUID, uuid);
+            this.idProperties = Collections.singletonList(idProperty);
+        } else {
+            this.idProperties = null;
+        }
     }
 
     /**
@@ -97,7 +117,7 @@
         CheckArg.isNotNull(path, "path");
         CheckArg.isNotNull(idProperty, "idProperty");
         this.path = path;
-        this.idProperties = Collections.singletonList(idProperty);
+        this.idProperties = idProperty != null ? Collections.singletonList(idProperty) : null;
     }
 
     /**
@@ -124,6 +144,25 @@
     }
 
     /**
+     * Create a location defined by a path and an iterator over identification properties.
+     * 
+     * @param path the path
+     * @param idProperties the iterator over the identification properties
+     * @throws IllegalArgumentException if any of the arguments are null
+     */
+    public Location( Path path,
+                     Iterable<Property> idProperties ) {
+        CheckArg.isNotNull(path, "path");
+        CheckArg.isNotNull(idProperties, "idProperties");
+        this.path = path;
+        List<Property> idPropertiesList = new ArrayList<Property>();
+        for (Property property : idProperties) {
+            idPropertiesList.add(property);
+        }
+        this.idProperties = Collections.unmodifiableList(idPropertiesList);
+    }
+
+    /**
      * Create a location defined by a single identification property.
      * 
      * @param idProperty the identification property
@@ -156,6 +195,22 @@
     }
 
     /**
+     * Create a location defined by a path and an iterator over identification properties.
+     * 
+     * @param idProperties the iterator over the identification properties
+     * @throws IllegalArgumentException if any of the arguments are null
+     */
+    public Location( Iterable<Property> idProperties ) {
+        CheckArg.isNotNull(idProperties, "idProperties");
+        this.path = null;
+        List<Property> idPropertiesList = new ArrayList<Property>();
+        for (Property property : idProperties) {
+            idPropertiesList.add(property);
+        }
+        this.idProperties = Collections.unmodifiableList(idPropertiesList);
+    }
+
+    /**
      * Create a location defined by multiple identification properties.
      * 
      * @param idProperties the identification properties
@@ -172,11 +227,10 @@
      * 
      * @param path the path
      * @param idProperties the identification properties
-     * @throws IllegalArgumentException if <code>path</code> or <code>idProperties</code> is null, or if <code>idProperties</code>
-     *         is empty
+     * @throws IllegalArgumentException if <code>path</code> is null, or if <code>idProperties</code> is empty
      */
-    public Location( Path path,
-                     List<Property> idProperties ) {
+    protected Location( Path path,
+                        List<Property> idProperties ) {
         CheckArg.isNotNull(path, "path");
         CheckArg.isNotEmpty(idProperties, "idProperties");
         this.path = path;
@@ -184,6 +238,50 @@
     }
 
     /**
+     * Create a location from another but adding the supplied identification property. The new identification property will
+     * replace any existing identification property with the same name on the original.
+     * 
+     * @param original the original location
+     * @param newIdProperty the new identification property
+     * @throws IllegalArgumentException if <code>original</code> is null
+     */
+    protected Location( Location original,
+                        Property newIdProperty ) {
+        CheckArg.isNotNull(original, "original");
+        this.path = original.getPath();
+        if (original.hasIdProperties()) {
+            List<Property> originalIdProperties = original.getIdProperties();
+            if (newIdProperty == null) {
+                this.idProperties = original.idProperties;
+            } else {
+                List<Property> idProperties = new ArrayList<Property>(originalIdProperties.size() + 1);
+                for (Property property : originalIdProperties) {
+                    if (!newIdProperty.getName().equals(property.getName())) idProperties.add(property);
+                }
+                idProperties.add(newIdProperty);
+                this.idProperties = Collections.unmodifiableList(idProperties);
+            }
+        } else {
+            this.idProperties = Collections.singletonList(newIdProperty);
+        }
+    }
+
+    /**
+     * Create a location from another but adding the supplied identification property. The new identification property will
+     * replace any existing identification property with the same name on the original.
+     * 
+     * @param original the original location
+     * @param newPath the new path for the location
+     * @throws IllegalArgumentException if <code>original</code> is null
+     */
+    protected Location( Location original,
+                        Path newPath ) {
+        CheckArg.isNotNull(original, "original");
+        this.path = newPath != null ? newPath : original.getPath();
+        this.idProperties = original.idProperties;
+    }
+
+    /**
      * Get the path that (at least in part) defines this location.
      * 
      * @return the path, or null if this location is not defined with a path
@@ -220,8 +318,108 @@
     }
 
     /**
+     * Get the identification property with the supplied name, if there is such a property.
+     * 
+     * @param name the name of the identification property
+     * @return the identification property with the supplied name, or null if there is no such property (or if there
+     *         {@link #hasIdProperties() are no identification properties}
+     */
+    public Property getIdProperty( Name name ) {
+        CheckArg.isNotNull(name, "name");
+        if (idProperties != null) {
+            for (Property property : idProperties) {
+                if (property.getName().equals(name)) return property;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Compare this location to the supplied location, and determine whether the two locations represent the same logical
+     * location. One location is considered the same as another location when one location is a superset of the other. For
+     * example, consider the following locations:
+     * <ul>
+     * <li>location A is defined with a "<code>/x/y</code>" path</li>
+     * <li>location B is defined with an identification property {id=3}</li>
+     * <li>location C is defined with a "<code>/x/y/z</code>"</li>
+     * <li>location D is defined with a "<code>/x/y/z</code>" path and an identification property {id=3}</li>
+     * </ul>
+     * Locations C and D would be considered the same, and B and D would also be considered the same. None of the other
+     * combinations would be considered the same.
+     * <p>
+     * Note that passing a null location as a parameter will always return false.
+     * </p>
+     * 
+     * @param other the other location to compare
+     * @return true if the two locations represent the same location, or false otherwise
+     */
+    public boolean isSame( Location other ) {
+        return isSame(other, true);
+    }
+
+    /**
+     * Compare this location to the supplied location, and determine whether the two locations represent the same logical
+     * location. One location is considered the same as another location when one location is a superset of the other. For
+     * example, consider the following locations:
+     * <ul>
+     * <li>location A is defined with a "<code>/x/y</code>" path</li>
+     * <li>location B is defined with an identification property {id=3}</li>
+     * <li>location C is defined with a "<code>/x/y/z</code>"</li>
+     * <li>location D is defined with a "<code>/x/y/z</code>" path and an identification property {id=3}</li>
+     * </ul>
+     * Locations C and D would be considered the same, and B and D would also be considered the same. None of the other
+     * combinations would be considered the same.
+     * <p>
+     * Note that passing a null location as a parameter will always return false.
+     * </p>
+     * 
+     * @param other the other location to compare
+     * @param requireSameNameSiblingIndexes true if the paths must have equivalent {@link Path.Segment#getIndex()
+     *        same-name-sibling indexes}, or false if the same-name-siblings may be different
+     * @return true if the two locations represent the same location, or false otherwise
+     */
+    public boolean isSame( Location other,
+                           boolean requireSameNameSiblingIndexes ) {
+        if (other != null) {
+            if (this.hasPath() && other.hasPath()) {
+                // Paths on both, so the paths MUST match
+                if (requireSameNameSiblingIndexes) {
+                    if (!this.getPath().equals(other.getPath())) return false;
+                } else {
+                    Path thisPath = this.getPath();
+                    Path thatPath = other.getPath();
+                    if (thisPath.isRoot() && thatPath.isRoot()) return true;
+                    // The parents must match ...
+                    if (!thisPath.hasSameAncestor(thatPath)) return false;
+                    // And the names of the last segments must match ...
+                    if (!thisPath.getLastSegment().getName().equals(thatPath.getLastSegment().getName())) return false;
+                }
+
+                // And the identification properties must match only if they exist on both
+                if (this.hasIdProperties() && other.hasIdProperties()) {
+                    return this.getIdProperties().containsAll(other.getIdProperties());
+                }
+                return true;
+            }
+            // Path only in one, so the identification properties MUST match
+            if (!other.hasIdProperties()) return false;
+            return this.getIdProperties().containsAll(other.getIdProperties());
+        }
+        return false;
+    }
+
+    /**
      * {@inheritDoc}
      * 
+     * @see java.lang.Iterable#iterator()
+     */
+    public Iterator<Property> iterator() {
+        return idProperties != null ? idProperties.iterator() : NO_ID_PROPERTIES_ITERATOR;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#hashCode()
      */
     @Override
@@ -272,4 +470,29 @@
         }
         return sb.toString();
     }
+
+    /**
+     * Create a copy of this location that adds the supplied identification property. The new identification property will replace
+     * any existing identification property with the same name on the original.
+     * 
+     * @param newIdProperty the new identification property, which may be null
+     * @return the new location, or this location if the new identification property is null or empty
+     */
+    public Location with( Property newIdProperty ) {
+        if (newIdProperty == null || newIdProperty.isEmpty()) return this;
+        return new Location(this, newIdProperty);
+    }
+
+    /**
+     * Create a copy of this location that uses the supplied path.
+     * 
+     * @param newPath the new path for the location
+     * @return the new location, or this location if the path is equal to this location's path
+     */
+    public Location with( Path newPath ) {
+        if (newPath == null) return this;
+        if (!this.path.equals(newPath)) return new Location(this, newPath);
+        return this;
+    }
+
 }

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Node.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Node.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Node.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -26,6 +26,7 @@
 import java.util.Map;
 import net.jcip.annotations.Immutable;
 import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
 
 /**
@@ -58,6 +59,22 @@
     Collection<Property> getProperties();
 
     /**
+     * Get the property with the supplied name.
+     * 
+     * @param name the property name
+     * @return the property, or null if there is no property by that name
+     */
+    Property getProperty( String name );
+
+    /**
+     * Get the property with the supplied name.
+     * 
+     * @param name the property name
+     * @return the property, or null if there is no property by that name
+     */
+    Property getProperty( Name name );
+
+    /**
      * Get the map of properties keyed by the property names.
      * 
      * @return the map of properties keyed by property name
@@ -72,6 +89,13 @@
     List<Location> getChildren();
 
     /**
+     * Get the list of child {@link Path.Segment segments}.
+     * 
+     * @return the list containing a segment for each child
+     */
+    List<Path.Segment> getChildrenSegments();
+
+    /**
      * Return whether this node has children.
      * 
      * @return true if the node has children, or false otherwise

Copied: trunk/dna-graph/src/main/java/org/jboss/dna/graph/NodeConflictBehavior.java (from rev 564, trunk/dna-graph/src/main/java/org/jboss/dna/graph/commands/NodeConflictBehavior.java)
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/NodeConflictBehavior.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/NodeConflictBehavior.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -0,0 +1,37 @@
+/*
+ * 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.graph;
+
+/**
+ * An enumeration used by several commands for the choice of handling duplicate nodes, such as when a node is to be copied to
+ * another location where a node already exists.
+ * 
+ * @author Randall Hauch
+ */
+public enum NodeConflictBehavior {
+
+    DO_NOT_REPLACE,
+    APPEND,
+    REPLACE,
+    UPDATE;
+
+}

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Subgraph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Subgraph.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Subgraph.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -51,4 +51,11 @@
      * @return the maximum depth requested; always positive
      */
     int getMaximumDepth();
+
+    /**
+     * Get the node that is at the {@link #getLocation() root} of the subgraph.
+     * 
+     * @return the root node in the subgraph
+     */
+    Node getRoot();
 }

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/RepositoryConnection.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/RepositoryConnection.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/RepositoryConnection.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -26,7 +26,6 @@
 import net.jcip.annotations.NotThreadSafe;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GraphCommand;
 import org.jboss.dna.graph.requests.Request;
 
 /**
@@ -85,16 +84,6 @@
      * Execute the supplied commands against this repository source.
      * 
      * @param context the environment in which the commands are being executed; never null
-     * @param commands the commands to be executed; never null
-     * @throws RepositorySourceException if there is a problem loading the node data
-     */
-    void execute( ExecutionContext context,
-                  GraphCommand... commands ) throws RepositorySourceException;
-
-    /**
-     * Execute the supplied commands against this repository source.
-     * 
-     * @param context the environment in which the commands are being executed; never null
      * @param request the request to be executed; never null
      * @throws RepositorySourceException if there is a problem loading the node data
      */

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/RepositoryConnectionPool.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/RepositoryConnectionPool.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connectors/RepositoryConnectionPool.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -41,7 +41,6 @@
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GraphCommand;
 import org.jboss.dna.graph.requests.Request;
 
 /**
@@ -980,15 +979,6 @@
 
         /**
          * {@inheritDoc}
-         */
-        public void execute( ExecutionContext context,
-                             GraphCommand... commands ) throws RepositorySourceException {
-            if (closed) throw new IllegalStateException(GraphI18n.closedConnectionMayNotBeUsed.text());
-            this.original.execute(context, commands);
-        }
-
-        /**
-         * {@inheritDoc}
          * 
          * @see org.jboss.dna.graph.connectors.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
          *      org.jboss.dna.graph.requests.Request)

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/PathNotFoundException.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/PathNotFoundException.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/PathNotFoundException.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -21,6 +21,8 @@
  */
 package org.jboss.dna.graph.properties;
 
+import org.jboss.dna.graph.Location;
+
 /**
  * @author Randall Hauch
  */
@@ -30,53 +32,57 @@
      */
     private static final long serialVersionUID = -3703984046286975978L;
 
-    private final Path path;
+    private final Location location;
     private final Path lowestAncestorThatDoesExist;
 
     /**
-     * @param path
-     * @param lowestAncestorThatDoesExist
+     * @param location the location of the node that does not exist
+     * @param lowestAncestorThatDoesExist the path of the lowest (closest) ancestor that does exist
      */
-    public PathNotFoundException( Path path, Path lowestAncestorThatDoesExist ) {
-        this.path = path;
+    public PathNotFoundException( Location location,
+                                  Path lowestAncestorThatDoesExist ) {
+        this.location = location;
         this.lowestAncestorThatDoesExist = lowestAncestorThatDoesExist;
     }
 
     /**
-     * @param path
-     * @param lowestAncestorThatDoesExist
+     * @param location the location of the node that does not exist
+     * @param lowestAncestorThatDoesExist the path of the lowest (closest) ancestor that does exist
      * @param message
      */
-    public PathNotFoundException( Path path, Path lowestAncestorThatDoesExist,
+    public PathNotFoundException( Location location,
+                                  Path lowestAncestorThatDoesExist,
                                   String message ) {
         super(message);
-        this.path = path;
+        this.location = location;
         this.lowestAncestorThatDoesExist = lowestAncestorThatDoesExist;
     }
 
     /**
-     * @param path
-     * @param lowestAncestorThatDoesExist
+     * @param location the location of the node that does not exist
+     * @param lowestAncestorThatDoesExist the path of the lowest (closest) ancestor that does exist
      * @param cause
      */
-    public PathNotFoundException( Path path, Path lowestAncestorThatDoesExist,
+    public PathNotFoundException( Location location,
+                                  Path lowestAncestorThatDoesExist,
                                   Throwable cause ) {
         super(cause);
-        this.path = path;
+        this.location = location;
         this.lowestAncestorThatDoesExist = lowestAncestorThatDoesExist;
     }
 
     /**
-     * @param path
-     * @param lowestAncestorThatDoesExist
+     * @param location the location of the node that does not exist
+     * @param lowestAncestorThatDoesExist the path of the lowest (closest) ancestor that does exist
      * @param message
      * @param cause
      */
-    public PathNotFoundException( Path path, Path lowestAncestorThatDoesExist,
+    public PathNotFoundException( Location location,
+                                  Path lowestAncestorThatDoesExist,
                                   String message,
                                   Throwable cause ) {
         super(message, cause);
-        this.path = path;
+        this.location = location;
         this.lowestAncestorThatDoesExist = lowestAncestorThatDoesExist;
     }
 
@@ -93,12 +99,13 @@
      * 
      * @return the path that was not found
      */
-    public Path getPath() {
-        return path;
+    public Location getLocation() {
+        return location;
     }
-    
+
     /**
-     * Get the lowest (closest) existing {@link Path#getParent() ancestor} of the {@link #getPath() non-existant path}.
+     * Get the lowest (closest) existing {@link Path#getParent() ancestor} of the {@link #getLocation() non-existant location}.
+     * 
      * @return the lowest ancestor that does exist
      */
     public Path getLowestAncestorThatDoesExist() {

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPath.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPath.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/properties/basic/BasicPath.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -269,9 +269,10 @@
      */
     public boolean hasSameAncestor( Path that ) {
         if (that == null) return false;
+        if (this.isRoot() && that.isRoot()) return true;
         if (that.size() != this.size()) return false;
-        if (this.size() == 1) return false;
-        for (int i = this.size() - 2; i < 0; --i) {
+        if (this.size() == 1) return true; // both nodes are just under the root
+        for (int i = this.size() - 2; i >= 0; --i) {
             Path.Segment thisSegment = this.getSegment(i);
             Path.Segment thatSegment = that.getSegment(i);
             if (!thisSegment.equals(thatSegment)) return false;
@@ -465,8 +466,9 @@
         if (beginIndex == 0) return this;
         int size = size();
         if (beginIndex >= size) {
-            throw new IndexOutOfBoundsException(GraphI18n.unableToCreateSubpathBeginIndexGreaterThanOrEqualToSize.text(beginIndex,
-                                                                                                                     size));
+            throw new IndexOutOfBoundsException(
+                                                GraphI18n.unableToCreateSubpathBeginIndexGreaterThanOrEqualToSize.text(beginIndex,
+                                                                                                                       size));
         }
         if (size == 0) return ROOT;
         return new BasicPath(this.segments.subList(beginIndex, size), this.isAbsolute());
@@ -483,13 +485,14 @@
             if (endIndex == size) return this;
         }
         if (beginIndex >= size) {
-            throw new IndexOutOfBoundsException(GraphI18n.unableToCreateSubpathBeginIndexGreaterThanOrEqualToSize.text(beginIndex,
-                                                                                                                     size));
+            throw new IndexOutOfBoundsException(
+                                                GraphI18n.unableToCreateSubpathBeginIndexGreaterThanOrEqualToSize.text(beginIndex,
+                                                                                                                       size));
         }
         if (beginIndex > endIndex) {
             throw new IndexOutOfBoundsException(
                                                 GraphI18n.unableToCreateSubpathBeginIndexGreaterThanOrEqualToEndingIndex.text(beginIndex,
-                                                                                                                            endIndex));
+                                                                                                                              endIndex));
         }
         // This reuses the same list, so it's pretty efficient ...
         return new BasicPath(this.segments.subList(beginIndex, endIndex), this.isAbsolute());

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CacheableRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CacheableRequest.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CacheableRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -0,0 +1,75 @@
+/*
+ * 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.graph.requests;
+
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.graph.cache.CachePolicy;
+import org.jboss.dna.graph.cache.Cacheable;
+import org.jboss.dna.graph.properties.DateTime;
+
+/**
+ * A request that contains results that may be cached.
+ * 
+ * @author Randall Hauch
+ */
+ at ThreadSafe
+public abstract class CacheableRequest extends Request implements Cacheable {
+
+    private static final long serialVersionUID = 1L;
+
+    private CachePolicy policy;
+    private DateTime timeLoaded;
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.cache.Cacheable#getCachePolicy()
+     */
+    public CachePolicy getCachePolicy() {
+        return policy;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.cache.Cacheable#getTimeLoaded()
+     */
+    public DateTime getTimeLoaded() {
+        return timeLoaded;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.cache.Cacheable#setCachePolicy(org.jboss.dna.graph.cache.CachePolicy)
+     */
+    public void setCachePolicy( CachePolicy cachePolicy ) {
+        policy = cachePolicy;
+    }
+
+    /**
+     * @param timeLoaded Sets timeLoaded to the specified value.
+     */
+    public void setTimeLoaded( DateTime timeLoaded ) {
+        this.timeLoaded = timeLoaded;
+    }
+}


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

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CompositeRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CompositeRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CompositeRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -35,6 +35,8 @@
  */
 public class CompositeRequest extends Request implements Iterable<Request> {
 
+    private static final long serialVersionUID = 1L;
+
     /**
      * Return a request that either wraps multiple requests, or the single request if only one is supplied.
      * 
@@ -48,18 +50,21 @@
             CheckArg.isNotNull(requests[0], "requests[0]");
             return requests[0];
         }
+        boolean readOnly = true;
         List<Request> list = new ArrayList<Request>(requests.length);
         for (Request request : requests) {
             if (request == null) continue;
             if (request instanceof CompositeRequest) {
                 CompositeRequest composite = (CompositeRequest)request;
                 list.addAll(composite.getRequests());
+                if (!composite.isReadOnly()) readOnly = false;
             } else {
                 list.add(request);
+                if (!request.isReadOnly()) readOnly = false;
             }
         }
         CheckArg.isNotEmpty(list, "requests");
-        return new CompositeRequest(list);
+        return new CompositeRequest(list, readOnly);
     }
 
     /**
@@ -69,8 +74,9 @@
      * @return the requests wrapped in a CompositeRequest, or if only one request is supplied that single request
      * @throws IllegalArgumentException if there requests are null, empty, or contains only nulls
      */
-    public static Request with( Iterator<Request> requests ) {
+    public static Request with( Iterator<? extends Request> requests ) {
         CheckArg.isNotNull(requests, "requests");
+        boolean readOnly = true;
         List<Request> list = new LinkedList<Request>();
         while (requests.hasNext()) {
             Request request = requests.next();
@@ -78,15 +84,17 @@
             if (request instanceof CompositeRequest) {
                 CompositeRequest composite = (CompositeRequest)request;
                 list.addAll(composite.getRequests());
+                if (!composite.isReadOnly()) readOnly = false;
             } else {
                 list.add(request);
+                if (!request.isReadOnly()) readOnly = false;
             }
         }
         if (list.size() == 1) {
             return list.get(0);
         }
         CheckArg.isNotEmpty(list, "requests");
-        return new CompositeRequest(list);
+        return new CompositeRequest(list, readOnly);
     }
 
     /**
@@ -96,12 +104,18 @@
      * @return the requests wrapped in a CompositeRequest, or if only one request is supplied that single request
      * @throws IllegalArgumentException if there requests are null or empty
      */
-    public static Request with( List<Request> requests ) {
+    public static Request with( List<? extends Request> requests ) {
         CheckArg.isNotEmpty(requests, "requests");
         if (requests.size() == 1) {
             return requests.get(0);
         }
-        return new CompositeRequest(requests);
+        boolean readOnly = true;
+        for (Request request : requests) {
+            if (request.isReadOnly()) continue;
+            readOnly = false;
+            break;
+        }
+        return new CompositeRequest(requests, readOnly);
     }
 
     /**
@@ -118,17 +132,20 @@
         CheckArg.isNotNull(composite, "composite");
         if (requests == null || requests.length == 0) return composite;
         List<Request> list = new ArrayList<Request>(requests.length + composite.size());
+        boolean readOnly = composite.isReadOnly();
         if (composite.size() != 0) list.addAll(composite.getRequests());
         for (Request request : requests) {
             if (request == null) continue;
             if (request instanceof CompositeRequest) {
                 CompositeRequest compositeRequest = (CompositeRequest)request;
                 list.addAll(compositeRequest.getRequests());
+                if (!compositeRequest.isReadOnly()) readOnly = false;
             } else {
                 list.add(request);
+                if (!request.isReadOnly()) readOnly = false;
             }
         }
-        return new CompositeRequest(list);
+        return new CompositeRequest(list, readOnly);
     }
 
     /**
@@ -141,9 +158,10 @@
      * @throws IllegalArgumentException if the composite request is null
      */
     public static CompositeRequest add( CompositeRequest composite,
-                                        Iterator<Request> requests ) {
+                                        Iterator<? extends Request> requests ) {
         CheckArg.isNotNull(composite, "composite");
         List<Request> list = new LinkedList<Request>();
+        boolean readOnly = composite.isReadOnly();
         if (composite.size() != 0) list.addAll(composite.getRequests());
         while (requests.hasNext()) {
             Request request = requests.next();
@@ -151,22 +169,28 @@
             if (request instanceof CompositeRequest) {
                 CompositeRequest compositeRequest = (CompositeRequest)request;
                 list.addAll(compositeRequest.getRequests());
+                if (!compositeRequest.isReadOnly()) readOnly = false;
             } else {
                 list.add(request);
+                if (!request.isReadOnly()) readOnly = false;
             }
         }
-        return new CompositeRequest(list);
+        return new CompositeRequest(list, readOnly);
     }
 
     private final List<Request> requests;
+    private final boolean readOnly;
 
     /**
      * Create a composite request from the supplied list of requests.
      * 
      * @param requests the modifiable list of requests; may not be null
+     * @param readOnly true if all of the requests are {@link Request#isReadOnly() read-only}
      */
-    protected CompositeRequest( List<Request> requests ) {
+    protected CompositeRequest( List<? extends Request> requests,
+                                boolean readOnly ) {
         this.requests = Collections.unmodifiableList(requests);
+        this.readOnly = readOnly;
     }
 
     /**
@@ -199,6 +223,16 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return readOnly;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CopyBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CopyBranchRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CopyBranchRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -22,7 +22,9 @@
 package org.jboss.dna.graph.requests;
 
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.NodeConflictBehavior;
 
 /**
  * Instruction that a branch be copied from one location into another.
@@ -31,8 +33,15 @@
  */
 public class CopyBranchRequest extends Request {
 
+    private static final long serialVersionUID = 1L;
+
+    public static final NodeConflictBehavior DEFAULT_CONFLICT_BEHAVIOR = NodeConflictBehavior.APPEND;
+
     private final Location from;
     private final Location into;
+    private final NodeConflictBehavior conflictBehavior;
+    private Location actualOldLocation;
+    private Location actualNewLocation;
 
     /**
      * Create a request to copy a branch to another.
@@ -43,10 +52,27 @@
      */
     public CopyBranchRequest( Location from,
                               Location into ) {
+        this(from, into, DEFAULT_CONFLICT_BEHAVIOR);
+    }
+
+    /**
+     * Create a request to copy a branch to another.
+     * 
+     * @param from the location of the top node in the existing branch that is to be copied
+     * @param into the location of the existing node into which the copy should be placed
+     * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
+     *        location
+     * @throws IllegalArgumentException if any of the parameters are null
+     */
+    public CopyBranchRequest( Location from,
+                              Location into,
+                              NodeConflictBehavior conflictBehavior ) {
         CheckArg.isNotNull(from, "from");
         CheckArg.isNotNull(into, "into");
+        CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
         this.from = from;
         this.into = into;
+        this.conflictBehavior = conflictBehavior;
     }
 
     /**
@@ -70,6 +96,74 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return false;
+    }
+
+    /**
+     * Get the expected behavior when copying the branch and the {@link #into() destination} already has a node with the same
+     * name.
+     * 
+     * @return the behavior specification
+     */
+    public NodeConflictBehavior conflictBehavior() {
+        return conflictBehavior;
+    }
+
+    /**
+     * Sets the actual and complete location of the node being renamed and its new location. This method must be called when
+     * processing the request, and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param oldLocation the actual location of the node before being renamed
+     * @param newLocation the actual location of the node after being renamed
+     * @throws IllegalArgumentException if the either location is null, if the old location does not represent the
+     *         {@link Location#isSame(Location) same location} as the {@link #from() from location}, if the new location does not
+     *         represent the {@link Location#isSame(Location) same location} as the {@link #into() into location}, or if the
+     *         either location does not have a path
+     */
+    public void setActualLocations( Location oldLocation,
+                                    Location newLocation ) {
+        if (!from.isSame(oldLocation)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(oldLocation, from));
+        }
+        if (!into.isSame(newLocation, false)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(newLocation, into));
+        }
+        assert oldLocation != null;
+        assert newLocation != null;
+        if (!oldLocation.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualOldLocationMustHavePath.text(oldLocation));
+        }
+        if (!newLocation.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualNewLocationMustHavePath.text(newLocation));
+        }
+        this.actualNewLocation = newLocation;
+    }
+
+    /**
+     * Get the actual location of the node before being copied.
+     * 
+     * @return the actual location of the node before being moved, or null if the actual location was not set
+     */
+    public Location getActualLocationBefore() {
+        return actualOldLocation;
+    }
+
+    /**
+     * Get the actual location of the node after being copied.
+     * 
+     * @return the actual location of the node after being moved, or null if the actual location was not set
+     */
+    public Location getActualLocationAfter() {
+        return actualNewLocation;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override
@@ -78,6 +172,7 @@
             CopyBranchRequest that = (CopyBranchRequest)obj;
             if (!this.from().equals(that.from())) return false;
             if (!this.into().equals(that.into())) return false;
+            if (!this.conflictBehavior().equals(that.conflictBehavior())) return false;
             return true;
         }
         return false;

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CreateNodeRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CreateNodeRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/CreateNodeRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -29,7 +29,9 @@
 import java.util.List;
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.NodeConflictBehavior;
 import org.jboss.dna.graph.properties.Property;
 
 /**
@@ -39,8 +41,14 @@
  */
 public class CreateNodeRequest extends Request implements Iterable<Property> {
 
+    private static final long serialVersionUID = 1L;
+
+    public static final NodeConflictBehavior DEFAULT_CONFLICT_BEHAVIOR = NodeConflictBehavior.APPEND;
+
     private final Location at;
     private final List<Property> properties;
+    private final NodeConflictBehavior conflictBehavior;
+    private Location actualLocation;
 
     /**
      * Create a request to create a node with the given properties at the supplied location.
@@ -52,8 +60,52 @@
      */
     public CreateNodeRequest( Location at,
                               Property... properties ) {
+        this(at, DEFAULT_CONFLICT_BEHAVIOR, properties);
+    }
+
+    /**
+     * Create a request to create a node with the given properties at the supplied location.
+     * 
+     * @param at the location of the node to be read
+     * @param properties the properties of the new node, which should not include the location's
+     *        {@link Location#getIdProperties() identification properties}
+     * @throws IllegalArgumentException if the location is null
+     */
+    public CreateNodeRequest( Location at,
+                              Iterable<Property> properties ) {
+        this(at, DEFAULT_CONFLICT_BEHAVIOR, properties);
+    }
+
+    /**
+     * Create a request to create a node with the given properties at the supplied location.
+     * 
+     * @param at the location of the node to be read
+     * @param properties the properties of the new node, which should not include the location's
+     *        {@link Location#getIdProperties() identification properties}
+     * @throws IllegalArgumentException if the location is null
+     */
+    public CreateNodeRequest( Location at,
+                              Iterator<Property> properties ) {
+        this(at, DEFAULT_CONFLICT_BEHAVIOR, properties);
+    }
+
+    /**
+     * Create a request to create a node with the given properties at the supplied location.
+     * 
+     * @param at the location of the node to be read
+     * @param properties the properties of the new node, which should not include the location's
+     *        {@link Location#getIdProperties() identification properties}
+     * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
+     *        location
+     * @throws IllegalArgumentException if the location or the conflict behavior is null
+     */
+    public CreateNodeRequest( Location at,
+                              NodeConflictBehavior conflictBehavior,
+                              Property... properties ) {
         CheckArg.isNotNull(at, "at");
+        CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
         this.at = at;
+        this.conflictBehavior = conflictBehavior;
         int number = properties.length + (at.hasIdProperties() ? at.getIdProperties().size() : 0);
         List<Property> props = new ArrayList<Property>(number);
         for (Property property : properties) {
@@ -74,12 +126,17 @@
      * @param at the location of the node to be read
      * @param properties the properties of the new node, which should not include the location's
      *        {@link Location#getIdProperties() identification properties}
-     * @throws IllegalArgumentException if the location is null
+     * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
+     *        location
+     * @throws IllegalArgumentException if the location or the conflict behavior is null
      */
     public CreateNodeRequest( Location at,
+                              NodeConflictBehavior conflictBehavior,
                               Iterable<Property> properties ) {
         CheckArg.isNotNull(at, "at");
+        CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
         this.at = at;
+        this.conflictBehavior = conflictBehavior;
         List<Property> props = new LinkedList<Property>();
         for (Property property : properties) {
             if (property != null) props.add(property);
@@ -99,12 +156,17 @@
      * @param at the location of the node to be read
      * @param properties the properties of the new node, which should not include the location's
      *        {@link Location#getIdProperties() identification properties}
-     * @throws IllegalArgumentException if the location is null
+     * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
+     *        location
+     * @throws IllegalArgumentException if the location or the conflict behavior is null
      */
     public CreateNodeRequest( Location at,
+                              NodeConflictBehavior conflictBehavior,
                               Iterator<Property> properties ) {
         CheckArg.isNotNull(at, "at");
+        CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
         this.at = at;
+        this.conflictBehavior = conflictBehavior;
         List<Property> props = new LinkedList<Property>();
         while (properties.hasNext()) {
             Property property = properties.next();
@@ -148,8 +210,55 @@
     }
 
     /**
+     * Get the expected behavior when copying the branch and the {@link #at() destination} already has a node with the same name.
+     * 
+     * @return the behavior specification
+     */
+    public NodeConflictBehavior conflictBehavior() {
+        return conflictBehavior;
+    }
+
+    /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return false;
+    }
+
+    /**
+     * Sets the actual and complete location of the node being created. This method must be called when processing the request,
+     * and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param actual the actual location of the node being created, or null if the {@link #at() current location} should be used
+     * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
+     *         location} as the {@link #at() current location}, or if the actual location does not have a path.
+     */
+    public void setActualLocationOfNode( Location actual ) {
+        if (!at.isSame(actual, false)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, at));
+        }
+        assert actual != null;
+        if (!actual.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
+        }
+        this.actualLocation = actual;
+    }
+
+    /**
+     * Get the actual location of the node that was created.
+     * 
+     * @return the actual location, or null if the actual location was not set
+     */
+    public Location getActualLocationOfNode() {
+        return actualLocation;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override
@@ -157,6 +266,7 @@
         if (this.getClass().isInstance(obj)) {
             CreateNodeRequest that = (CreateNodeRequest)obj;
             if (!this.at().equals(that.at())) return false;
+            if (!this.conflictBehavior().equals(that.conflictBehavior())) return false;
             if (!this.properties().equals(that.properties())) return false;
             return true;
         }

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/DeleteBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/DeleteBranchRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/DeleteBranchRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -22,6 +22,7 @@
 package org.jboss.dna.graph.requests;
 
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 
 /**
@@ -31,7 +32,10 @@
  */
 public class DeleteBranchRequest extends Request {
 
+    private static final long serialVersionUID = 1L;
+
     private final Location at;
+    private Location actualLocation;
 
     /**
      * Create a request to delete a branch.
@@ -56,6 +60,44 @@
     /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return false;
+    }
+
+    /**
+     * Sets the actual and complete location of the node being deleted. This method must be called when processing the request,
+     * and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param actual the actual location of the node being deleted, or null if the {@link #at() current location} should be used
+     * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
+     *         location} as the {@link #at() current location}, or if the actual location does not have a path.
+     */
+    public void setActualLocationOfNode( Location actual ) {
+        if (!at.isSame(actual)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, at));
+        }
+        assert actual != null;
+        if (!actual.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
+        }
+        this.actualLocation = actual;
+    }
+
+    /**
+     * Get the actual location of the node that was deleted.
+     * 
+     * @return the actual location, or null if the actual location was not set
+     */
+    public Location getActualLocationOfNode() {
+        return actualLocation;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/MoveBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/MoveBranchRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/MoveBranchRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -22,7 +22,9 @@
 package org.jboss.dna.graph.requests;
 
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.NodeConflictBehavior;
 
 /**
  * Instruction that a branch be moved from one location into another.
@@ -31,8 +33,15 @@
  */
 public class MoveBranchRequest extends Request {
 
+    private static final long serialVersionUID = 1L;
+
+    public static final NodeConflictBehavior DEFAULT_CONFLICT_BEHAVIOR = NodeConflictBehavior.APPEND;
+
     private final Location from;
     private final Location into;
+    private final NodeConflictBehavior conflictBehavior;
+    private Location actualOldLocation;
+    private Location actualNewLocation;
 
     /**
      * Create a request to move a branch from one location into another.
@@ -43,10 +52,27 @@
      */
     public MoveBranchRequest( Location from,
                               Location into ) {
+        this(from, into, DEFAULT_CONFLICT_BEHAVIOR);
+    }
+
+    /**
+     * Create a request to move a branch from one location into another.
+     * 
+     * @param from the location of the top node in the existing branch that is to be moved
+     * @param into the location of the existing node into which the branch should be moved
+     * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
+     *        location
+     * @throws IllegalArgumentException if any of the parameters are null
+     */
+    public MoveBranchRequest( Location from,
+                              Location into,
+                              NodeConflictBehavior conflictBehavior ) {
         CheckArg.isNotNull(from, "from");
         CheckArg.isNotNull(into, "into");
+        CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
         this.from = from;
         this.into = into;
+        this.conflictBehavior = conflictBehavior;
     }
 
     /**
@@ -68,8 +94,76 @@
     }
 
     /**
+     * Get the expected behavior when copying the branch and the {@link #into() destination} already has a node with the same
+     * name.
+     * 
+     * @return the behavior specification
+     */
+    public NodeConflictBehavior conflictBehavior() {
+        return conflictBehavior;
+    }
+
+    /**
      * {@inheritDoc}
      * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return false;
+    }
+
+    /**
+     * Sets the actual and complete location of the node being renamed and its new location. This method must be called when
+     * processing the request, and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param oldLocation the actual location of the node before being renamed
+     * @param newLocation the actual location of the node after being renamed
+     * @throws IllegalArgumentException if the either location is null, if the old location does not represent the
+     *         {@link Location#isSame(Location) same location} as the {@link #from() from location}, if the new location does not
+     *         represent the {@link Location#isSame(Location) same location} as the {@link #into() into location}, or if the
+     *         either location does not have a path
+     */
+    public void setActualLocations( Location oldLocation,
+                                    Location newLocation ) {
+        if (!from.isSame(oldLocation)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(oldLocation, from));
+        }
+        if (!into.isSame(newLocation, false)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(newLocation, into));
+        }
+        assert oldLocation != null;
+        assert newLocation != null;
+        if (!oldLocation.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualOldLocationMustHavePath.text(oldLocation));
+        }
+        if (!newLocation.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualNewLocationMustHavePath.text(newLocation));
+        }
+        this.actualNewLocation = newLocation;
+    }
+
+    /**
+     * Get the actual location of the node before being moved.
+     * 
+     * @return the actual location of the node before being moved, or null if the actual location was not set
+     */
+    public Location getActualLocationBefore() {
+        return actualOldLocation;
+    }
+
+    /**
+     * Get the actual location of the node after being moved.
+     * 
+     * @return the actual location of the node after being moved, or null if the actual location was not set
+     */
+    public Location getActualLocationAfter() {
+        return actualNewLocation;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
      * @see java.lang.Object#equals(java.lang.Object)
      */
     @Override
@@ -78,6 +172,7 @@
             MoveBranchRequest that = (MoveBranchRequest)obj;
             if (!this.from().equals(that.from())) return false;
             if (!this.into().equals(that.into())) return false;
+            if (!this.conflictBehavior().equals(that.conflictBehavior())) return false;
             return true;
         }
         return false;

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadAllChildrenRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadAllChildrenRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadAllChildrenRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -25,6 +25,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.properties.Path;
@@ -35,10 +36,13 @@
  * 
  * @author Randall Hauch
  */
-public class ReadAllChildrenRequest extends Request implements Iterable<Location> {
+public class ReadAllChildrenRequest extends CacheableRequest implements Iterable<Location> {
 
+    private static final long serialVersionUID = 1L;
+
     private final Location of;
     private final List<Location> children = new LinkedList<Location>();
+    private Location actualOf;
 
     /**
      * Create a request to read the children of a node at the supplied location.
@@ -52,6 +56,16 @@
     }
 
     /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return true;
+    }
+
+    /**
      * Get the location defining the node whose children are to be read.
      * 
      * @return the location of the parent node; never null
@@ -128,6 +142,34 @@
     }
 
     /**
+     * Sets the actual and complete location of the node whose children have been read. This method must be called when processing
+     * the request, and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param actual the actual location of the node being read, or null if the {@link #of() current location} should be used
+     * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
+     *         location} as the {@link #of() current location}, or if the actual location does not have a path.
+     */
+    public void setActualLocationOfNode( Location actual ) {
+        if (!this.of.isSame(actual)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, of));
+        }
+        assert actual != null;
+        if (!actual.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
+        }
+        this.actualOf = actual;
+    }
+
+    /**
+     * Get the actual location of the node whose children were read.
+     * 
+     * @return the actual location, or null if the actual location was not set
+     */
+    public Location getActualLocationOfNode() {
+        return actualOf;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#equals(java.lang.Object)

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadAllPropertiesRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadAllPropertiesRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadAllPropertiesRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -26,6 +26,7 @@
 import java.util.Iterator;
 import java.util.Map;
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.properties.Name;
@@ -36,13 +37,16 @@
  * 
  * @author Randall Hauch
  */
-public class ReadAllPropertiesRequest extends Request implements Iterable<Property> {
+public class ReadAllPropertiesRequest extends CacheableRequest implements Iterable<Property> {
 
+    private static final long serialVersionUID = 1L;
+
     public static final int UNKNOWN_NUMBER_OF_CHILDREN = -1;
 
     private final Location at;
     private final Map<Name, Property> properties = new HashMap<Name, Property>();
     private int numberOfChildren = UNKNOWN_NUMBER_OF_CHILDREN;
+    private Location actualLocation;
 
     /**
      * Create a request to read the properties and number of children of a node at the supplied location.
@@ -56,6 +60,16 @@
     }
 
     /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return true;
+    }
+
+    /**
      * Get the location defining the node that is to be read.
      * 
      * @return the location of the node; never null
@@ -136,6 +150,34 @@
     }
 
     /**
+     * Sets the actual and complete location of the node whose properties have been read. This method must be called when
+     * processing the request, and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param actual the actual location of the node being read, or null if the {@link #at() current location} should be used
+     * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
+     *         location} as the {@link #at() current location}, or if the actual location does not have a path.
+     */
+    public void setActualLocationOfNode( Location actual ) {
+        if (!at.isSame(actual)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, at));
+        }
+        assert actual != null;
+        if (!actual.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
+        }
+        this.actualLocation = actual;
+    }
+
+    /**
+     * Get the actual location of the node whose properties were read.
+     * 
+     * @return the actual location, or null if the actual location was not set
+     */
+    public Location getActualLocationOfNode() {
+        return actualLocation;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#equals(java.lang.Object)

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadBlockOfChildrenRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadBlockOfChildrenRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadBlockOfChildrenRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -25,6 +25,7 @@
 import java.util.List;
 import org.jboss.dna.common.text.Inflector;
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.properties.Path;
@@ -37,12 +38,15 @@
  * 
  * @author Randall Hauch
  */
-public class ReadBlockOfChildrenRequest extends Request {
+public class ReadBlockOfChildrenRequest extends CacheableRequest {
 
+    private static final long serialVersionUID = 1L;
+
     private final Location of;
     private final List<Location> children = new LinkedList<Location>();
     private final int startingAt;
     private final int count;
+    private Location actualLocation;
 
     /**
      * Create a request to read a block of the children of a node at the supplied location. The block is defined by the starting
@@ -68,6 +72,16 @@
     }
 
     /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return true;
+    }
+
+    /**
      * Get the location defining the node whose children are to be read.
      * 
      * @return the location of the parent node; never null
@@ -171,6 +185,34 @@
     }
 
     /**
+     * Sets the actual and complete location of the node whose children have been read. This method must be called when processing
+     * the request, and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param actual the actual location of the node being read, or null if the {@link #of() current location} should be used
+     * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
+     *         location} as the {@link #of() current location}, or if the actual location does not have a path.
+     */
+    public void setActualLocationOfNode( Location actual ) {
+        if (!of.isSame(actual)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, of));
+        }
+        assert actual != null;
+        if (!actual.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
+        }
+        this.actualLocation = actual;
+    }
+
+    /**
+     * Get the actual location of the node whose children were read.
+     * 
+     * @return the actual location, or null if the actual location was not set
+     */
+    public Location getActualLocationOfNode() {
+        return actualLocation;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#equals(java.lang.Object)

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadBranchRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadBranchRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -27,11 +27,14 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import net.jcip.annotations.NotThreadSafe;
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
 
 /**
@@ -41,14 +44,43 @@
  * @author Randall Hauch
  */
 @NotThreadSafe
-public class ReadBranchRequest extends Request implements Iterable<Location> {
+public class ReadBranchRequest extends CacheableRequest implements Iterable<Location> {
 
+    private static final long serialVersionUID = 1L;
+
     public static final int DEFAULT_MAXIMUM_DEPTH = 2;
 
+    private static class Node {
+        private final Location location;
+        private final Map<Name, Property> properties = new HashMap<Name, Property>();
+        private List<Location> children;
+
+        protected Node( Location location ) {
+            assert location != null;
+            this.location = location;
+        }
+
+        protected Location getLocation() {
+            return location;
+        }
+
+        protected Map<Name, Property> getProperties() {
+            return properties;
+        }
+
+        protected List<Location> getChildren() {
+            return children;
+        }
+
+        protected void setChildren( List<Location> children ) {
+            this.children = children;
+        }
+    }
+
     private final Location at;
     private final int maxDepth;
-    private final Map<Location, Map<Name, Property>> nodeProperties = new HashMap<Location, Map<Name, Property>>();
-    private final Map<Location, List<Location>> children = new HashMap<Location, List<Location>>();
+    private final Map<Path, Node> nodes = new HashMap<Path, Node>();
+    private Location actualLocation;
 
     /**
      * Create a request to read the branch at the supplied location, to a maximum depth of 2.
@@ -78,6 +110,16 @@
     }
 
     /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return true;
+    }
+
+    /**
      * Get the location defining the top of the branch to be deleted
      * 
      * @return the location of the branch; never null
@@ -102,25 +144,50 @@
      * @return true if this branch includes the location, or false otherwise
      */
     public boolean includes( Location location ) {
-        return this.nodeProperties.containsKey(location);
+        if (location == null || !location.hasPath()) return false;
+        return this.nodes.containsKey(location.getPath());
     }
 
     /**
+     * Return whether this branch contains the specified path.
+     * 
+     * @param path the path
+     * @return true if this branch includes the path, or false otherwise
+     */
+    public boolean includes( Path path ) {
+        if (path == null) return false;
+        return this.nodes.containsKey(path);
+    }
+
+    /**
+     * Get the location for the supplied path.
+     * 
+     * @param path the path
+     * @return the location for the path, or null if the path is not known
+     */
+    public Location getLocationFor( Path path ) {
+        Node node = nodes.get(path);
+        return node != null ? node.getLocation() : null;
+    }
+
+    /**
      * Add a node that was read from the {@link RepositoryConnection}. This method does not verify or check that the node is
      * indeed on the branch and that it is at a level prescribed by the request.
      * 
-     * @param node the location of the node that appears on this branch.
+     * @param node the location of the node that appears on this branch; must {@link Location#hasPath() have a path}
      * @param properties the properties on the node
      * @throws IllegalArgumentException if the node is null
      */
     public void setProperties( Location node,
                                Property... properties ) {
         CheckArg.isNotNull(node, "node");
-        Map<Name, Property> propertiesMap = nodeProperties.get(node);
-        if (propertiesMap == null) {
-            propertiesMap = new HashMap<Name, Property>();
-            nodeProperties.put(node, propertiesMap);
+        assert node.hasPath();
+        Node nodeObj = nodes.get(node.getPath());
+        if (nodeObj == null) {
+            nodeObj = new Node(node);
+            nodes.put(node.getPath(), nodeObj);
         }
+        Map<Name, Property> propertiesMap = nodeObj.getProperties();
         for (Property property : properties) {
             propertiesMap.put(property.getName(), property);
         }
@@ -130,18 +197,20 @@
      * Add a node that was read from the {@link RepositoryConnection}. This method does not verify or check that the node is
      * indeed on the branch and that it is at a level prescribed by the request.
      * 
-     * @param node the location of the node that appears on this branch.
+     * @param node the location of the node that appears on this branch; must {@link Location#hasPath() have a path}
      * @param properties the properties on the node
      * @throws IllegalArgumentException if the node is null
      */
     public void setProperties( Location node,
                                Iterable<Property> properties ) {
         CheckArg.isNotNull(node, "node");
-        Map<Name, Property> propertiesMap = nodeProperties.get(node);
-        if (propertiesMap == null) {
-            propertiesMap = new HashMap<Name, Property>();
-            nodeProperties.put(node, propertiesMap);
+        assert node.hasPath();
+        Node nodeObj = nodes.get(node.getPath());
+        if (nodeObj == null) {
+            nodeObj = new Node(node);
+            nodes.put(node.getPath(), nodeObj);
         }
+        Map<Name, Property> propertiesMap = nodeObj.getProperties();
         for (Property property : properties) {
             propertiesMap.put(property.getName(), property);
         }
@@ -150,50 +219,65 @@
     /**
      * Record the children for a parent node in the branch.
      * 
-     * @param parent the location of the parent
+     * @param parent the location of the parent; must {@link Location#hasPath() have a path}
      * @param children the location of each child, in the order they appear in the parent
      */
     public void setChildren( Location parent,
                              Location... children ) {
         CheckArg.isNotNull(parent, "parent");
         CheckArg.isNotNull(children, "children");
-        this.children.put(parent, Arrays.asList(children));
+        assert parent.hasPath();
+        Node nodeObj = nodes.get(parent.getPath());
+        if (nodeObj == null) {
+            nodeObj = new Node(parent);
+            nodes.put(parent.getPath(), nodeObj);
+        }
+        nodeObj.setChildren(Arrays.asList(children));
     }
 
     /**
      * Record the children for a parent node in the branch.
      * 
-     * @param parent the location of the parent
+     * @param parent the location of the parent; must {@link Location#hasPath() have a path}
      * @param children the location of each child, in the order they appear in the parent
      */
     public void setChildren( Location parent,
                              List<Location> children ) {
         CheckArg.isNotNull(parent, "parent");
         CheckArg.isNotNull(children, "children");
-        this.children.put(parent, children);
+        assert parent.hasPath();
+        Node nodeObj = nodes.get(parent.getPath());
+        if (nodeObj == null) {
+            nodeObj = new Node(parent);
+            nodes.put(parent.getPath(), nodeObj);
+        }
+        nodeObj.setChildren(children);
     }
 
-    /**
-     * Get the nodes that make up this branch. If this map is empty, the branch has not yet been read. The resulting map maintains
-     * the order that the nodes were {@link #setProperties(Location, Property...) added}.
-     * 
-     * @return the branch information
-     * @see #iterator()
-     */
-    public Map<Location, Map<Name, Property>> getPropertiesByNode() {
-        return nodeProperties;
-    }
+    // /**
+    // * Get the nodes that make up this branch. If this map is empty, the branch has not yet been read. The resulting map
+    // maintains
+    // * the order that the nodes were {@link #setProperties(Location, Property...) added}.
+    // *
+    // * @return the branch information
+    // * @see #iterator()
+    // */
+    // public Map<Path, Map<Name, Property>> getPropertiesByNode() {
+    // return nodeProperties;
+    // }
 
     /**
      * Get the nodes that make up this branch. If this map is empty, the branch has not yet been read. The resulting map maintains
      * the order that the nodes were {@link #setProperties(Location, Property...) added}.
      * 
      * @param location the location of the node for which the properties are to be obtained
-     * @return the properties for the location, as a map keyed by the property name
+     * @return the properties for the location, as a map keyed by the property name, or null if there is no such location
      * @see #iterator()
      */
     public Map<Name, Property> getPropertiesFor( Location location ) {
-        return nodeProperties.get(location);
+        if (location == null || !location.hasPath()) return null;
+        Node node = nodes.get(location.getPath());
+        return node != null ? node.getProperties() : null;
     }
 
     /**
@@ -203,8 +287,9 @@
      * @return the children, or null if there are no children (or if the parent has not been read)
      */
     public List<Location> getChildren( Location parent ) {
-        CheckArg.isNotNull(parent, "parent");
-        return this.children.get(parent);
+        if (parent == null || !parent.hasPath()) return null;
+        Node node = nodes.get(parent.getPath());
+        return node != null ? node.getChildren() : null;
     }
 
     /**
@@ -217,7 +302,10 @@
      */
     public Iterator<Location> iterator() {
         final LinkedList<Location> queue = new LinkedList<Location>();
-        queue.addFirst(at());
+        if (getActualLocationOfNode() != null) {
+            Location actual = getActualLocationOfNode();
+            if (actual != null) queue.addFirst(getActualLocationOfNode());
+        }
         return new Iterator<Location>() {
             public boolean hasNext() {
                 return queue.peek() != null;
@@ -226,6 +314,7 @@
             public Location next() {
                 // Add the children of the next node to the queue ...
                 Location next = queue.poll();
+                if (next == null) throw new NoSuchElementException();
                 List<Location> children = getChildren(next);
                 if (children != null && children.size() > 0) queue.addAll(0, children);
                 return next;
@@ -238,6 +327,34 @@
     }
 
     /**
+     * Sets the actual and complete location of the node being read. This method must be called when processing the request, and
+     * the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param actual the actual location of the node being read, or null if the {@link #at() current location} should be used
+     * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
+     *         location} as the {@link #at() current location}, or if the actual location does not have a path.
+     */
+    public void setActualLocationOfNode( Location actual ) {
+        if (!at.isSame(actual)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, at));
+        }
+        assert actual != null;
+        if (!actual.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
+        }
+        this.actualLocation = actual;
+    }
+
+    /**
+     * Get the actual location of the node that was read.
+     * 
+     * @return the actual location, or null if the actual location was not set
+     */
+    public Location getActualLocationOfNode() {
+        return actualLocation;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#equals(java.lang.Object)

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadNodeRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadNodeRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadNodeRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -28,6 +28,7 @@
 import java.util.List;
 import java.util.Map;
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.properties.Name;
@@ -39,11 +40,14 @@
  * 
  * @author Randall Hauch
  */
-public class ReadNodeRequest extends Request implements Iterable<Location> {
+public class ReadNodeRequest extends CacheableRequest implements Iterable<Location> {
 
+    private static final long serialVersionUID = 1L;
+
     private final Location at;
     private final Map<Name, Property> properties = new HashMap<Name, Property>();
     private final List<Location> children = new LinkedList<Location>();
+    private Location actualLocation;
 
     /**
      * Create a request to read the properties and number of children of a node at the supplied location.
@@ -57,6 +61,16 @@
     }
 
     /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return true;
+    }
+
+    /**
      * Get the location defining the node that is to be read.
      * 
      * @return the location of the node; never null
@@ -175,6 +189,34 @@
     }
 
     /**
+     * Sets the actual and complete location of the node whose children and properties have been read. This method must be called
+     * when processing the request, and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param actual the actual location of the node being read, or null if the {@link #at() current location} should be used
+     * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
+     *         location} as the {@link #at() current location}, or if the actual location does not have a path.
+     */
+    public void setActualLocationOfNode( Location actual ) {
+        if (!at.isSame(actual)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, at));
+        }
+        assert actual != null;
+        if (!actual.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
+        }
+        this.actualLocation = actual;
+    }
+
+    /**
+     * Get the actual location of the node whose children and properties were read.
+     * 
+     * @return the actual location, or null if the actual location was not set
+     */
+    public Location getActualLocationOfNode() {
+        return actualLocation;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#equals(java.lang.Object)

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadPropertyRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadPropertyRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/ReadPropertyRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -22,6 +22,7 @@
 package org.jboss.dna.graph.requests;
 
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.properties.Name;
@@ -32,11 +33,14 @@
  * 
  * @author Randall Hauch
  */
-public class ReadPropertyRequest extends Request {
+public class ReadPropertyRequest extends CacheableRequest {
 
+    private static final long serialVersionUID = 1L;
+
     private final Location on;
     private final Name propertyName;
     private Property property;
+    private Location actualLocation;
 
     /**
      * Create a request to read the properties and number of children of a node at the supplied location.
@@ -54,6 +58,16 @@
     }
 
     /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return true;
+    }
+
+    /**
      * Get the location defining the node that is to be read.
      * 
      * @return the location of the node; never null
@@ -93,6 +107,34 @@
     }
 
     /**
+     * Sets the actual and complete location of the node whose property has been read. This method must be called when processing
+     * the request, and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param actual the actual location of the node being read, or null if the {@link #on() current location} should be used
+     * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
+     *         location} as the {@link #on() current location}, or if the actual location does not have a path.
+     */
+    public void setActualLocationOfNode( Location actual ) {
+        if (!on.isSame(actual)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, on));
+        }
+        assert actual != null;
+        if (!actual.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
+        }
+        this.actualLocation = actual;
+    }
+
+    /**
+     * Get the actual location of the node whose property was read.
+     * 
+     * @return the actual location, or null if the actual location was not set
+     */
+    public Location getActualLocationOfNode() {
+        return actualLocation;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#equals(java.lang.Object)

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RemovePropertiesRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RemovePropertiesRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RemovePropertiesRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -28,6 +28,7 @@
 import java.util.Set;
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.Name;
 
@@ -38,8 +39,11 @@
  */
 public class RemovePropertiesRequest extends Request implements Iterable<Name> {
 
+    private static final long serialVersionUID = 1L;
+
     private final Location from;
     private final Set<Name> propertyNames;
+    private Location actualLocation;
 
     /**
      * Create a request to remove the properties with the given names from the node at the supplied location.
@@ -100,6 +104,16 @@
     }
 
     /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return false;
+    }
+
+    /**
      * Get the location defining the node from which the properties are to be removed.
      * 
      * @return the location of the node; never null
@@ -127,6 +141,34 @@
     }
 
     /**
+     * Sets the actual and complete location of the node whose properties were removed. This method must be called when processing
+     * the request, and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param actual the actual location of the node being changed, or null if the {@link #from() current location} should be used
+     * @throws IllegalArgumentException if the actual location does not represent the {@link Location#isSame(Location) same
+     *         location} as the {@link #from() current location}, or if the actual location does not have a path.
+     */
+    public void setActualLocationOfNode( Location actual ) {
+        if (!from.isSame(actual)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, from));
+        }
+        assert actual != null;
+        if (!actual.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
+        }
+        this.actualLocation = actual;
+    }
+
+    /**
+     * Get the actual location of the node whose properties were removed.
+     * 
+     * @return the actual location, or null if the actual location was not set
+     */
+    public Location getActualLocationOfNode() {
+        return actualLocation;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#equals(java.lang.Object)

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RenameNodeRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RenameNodeRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RenameNodeRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -22,8 +22,10 @@
 package org.jboss.dna.graph.requests;
 
 import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.Path;
 
 /**
  * Instruction to rename an existing node (but keep it under the same parent). The same-name-sibling index will be determined
@@ -33,8 +35,12 @@
  */
 public class RenameNodeRequest extends Request {
 
+    private static final long serialVersionUID = 1L;
+
     private final Location at;
     private final Name newName;
+    private Location actualOldLocation;
+    private Location actualNewLocation;
 
     /**
      * Create a request to rename the node at the supplied location.
@@ -52,6 +58,16 @@
     }
 
     /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return false;
+    }
+
+    /**
      * Get the location defining the node that is to be read.
      * 
      * @return the location of the node; never null
@@ -70,6 +86,63 @@
     }
 
     /**
+     * Sets the actual and complete location of the node being renamed and its new location. This method must be called when
+     * processing the request, and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param oldLocation the actual location of the node before being renamed
+     * @param newLocation the actual location of the node after being renamed
+     * @throws IllegalArgumentException if the either location is null or is missing its path, if the old location does not
+     *         represent the {@link Location#isSame(Location) same location} as the {@link #at() current location}, if the new
+     *         location does not have the same parent as the old location, or if the new location does not have the same
+     *         {@link Path.Segment#getName() name} on {@link Path#getLastSegment() last segment} as that {@link #toName()
+     *         specified on the request}
+     */
+    public void setActualLocations( Location oldLocation,
+                                    Location newLocation ) {
+        if (!at.isSame(oldLocation)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(oldLocation, at));
+        }
+        assert oldLocation != null;
+        if (newLocation == null) {
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(newLocation, at));
+        }
+        if (!oldLocation.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualOldLocationMustHavePath.text(oldLocation));
+        }
+        if (!newLocation.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualNewLocationMustHavePath.text(newLocation));
+        }
+        Path newPath = newLocation.getPath();
+        if (!newPath.getParent().equals(oldLocation.getPath().getParent())) {
+            String msg = GraphI18n.actualNewLocationMustHaveSameParentAsOldLocation.text(newLocation, oldLocation);
+            throw new IllegalArgumentException(msg);
+        }
+        if (!newPath.getLastSegment().getName().equals(toName())) {
+            String msg = GraphI18n.actualNewLocationMustHaveSameNameAsRequest.text(newLocation, toName());
+            throw new IllegalArgumentException(msg);
+        }
+        this.actualNewLocation = newLocation;
+    }
+
+    /**
+     * Get the actual location of the node before being renamed.
+     * 
+     * @return the actual location of the node before being renamed, or null if the actual location was not set
+     */
+    public Location getActualLocationBefore() {
+        return actualOldLocation;
+    }
+
+    /**
+     * Get the actual location of the node after being renamed.
+     * 
+     * @return the actual location of the node after being renamed, or null if the actual location was not set
+     */
+    public Location getActualLocationAfter() {
+        return actualNewLocation;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#equals(java.lang.Object)

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/Request.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/Request.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/Request.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -21,6 +21,7 @@
  */
 package org.jboss.dna.graph.requests;
 
+import java.io.Serializable;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 
 /**
@@ -28,8 +29,10 @@
  * 
  * @author Randall Hauch
  */
-public abstract class Request {
+public abstract class Request implements Serializable {
 
+    private static final long serialVersionUID = 1L;
+
     private Throwable error;
 
     /**
@@ -59,4 +62,11 @@
         return error;
     }
 
+    /**
+     * Return whether this request only reads information.
+     * 
+     * @return true if this request reads information, or false if it requests that the repository content be changed in some way
+     */
+    public abstract boolean isReadOnly();
+
 }

Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RequestProcessor.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RequestProcessor.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,421 +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.graph.requests;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Queue;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.GraphI18n;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.connectors.RepositorySourceException;
-import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Property;
-import org.jboss.dna.graph.properties.basic.BasicEmptyProperty;
-
-/**
- * A component that is used to process and execute {@link Request}s. This class is intended to be subclassed and methods
- * overwritten to define the behavior for executing the different kinds of requests. Abstract methods must be overridden, but
- * non-abstract methods all have meaningful default implementations.
- * 
- * @author Randall Hauch
- */
- at Immutable
-public abstract class RequestProcessor {
-
-    private final ExecutionContext context;
-    private final String sourceName;
-
-    protected RequestProcessor( String sourceName,
-                                ExecutionContext context ) {
-        CheckArg.isNotEmpty(sourceName, "sourceName");
-        CheckArg.isNotNull(context, "context");
-        this.context = context;
-        this.sourceName = sourceName;
-    }
-
-    /**
-     * Get the name of the source against which this processor is executing.
-     * 
-     * @return the repository source name; never null or empty
-     */
-    public String getSourceName() {
-        return sourceName;
-    }
-
-    /**
-     * The execution context that this process is operating within.
-     * 
-     * @return the execution context; never null
-     */
-    public ExecutionContext getExecutionContext() {
-        return this.context;
-    }
-
-    /**
-     * Process a request by determining the type of request and delegating to the appropriate <code>process</code> method for that
-     * type.
-     * <p>
-     * This method does nothing if the request is null.
-     * </p>
-     * 
-     * @param request the general request
-     */
-    public void process( Request request ) {
-        if (request == null) return;
-        if (request instanceof CompositeRequest) {
-            process((CompositeRequest)request);
-        } else if (request instanceof CopyBranchRequest) {
-            process((CopyBranchRequest)request);
-        } else if (request instanceof CreateNodeRequest) {
-            process((CreateNodeRequest)request);
-        } else if (request instanceof DeleteBranchRequest) {
-            process((DeleteBranchRequest)request);
-        } else if (request instanceof MoveBranchRequest) {
-            process((MoveBranchRequest)request);
-        } else if (request instanceof ReadAllChildrenRequest) {
-            process((ReadAllChildrenRequest)request);
-        } else if (request instanceof ReadBlockOfChildrenRequest) {
-            process((ReadBlockOfChildrenRequest)request);
-        } else if (request instanceof ReadBranchRequest) {
-            process((ReadBranchRequest)request);
-        } else if (request instanceof ReadNodeRequest) {
-            process((ReadNodeRequest)request);
-        } else if (request instanceof ReadAllPropertiesRequest) {
-            process((ReadAllPropertiesRequest)request);
-        } else if (request instanceof ReadPropertyRequest) {
-            process((ReadPropertyRequest)request);
-        } else if (request instanceof RemovePropertiesRequest) {
-            process((RemovePropertiesRequest)request);
-        } else if (request instanceof RenameNodeRequest) {
-            process((RenameNodeRequest)request);
-        } else if (request instanceof UpdatePropertiesRequest) {
-            process((UpdatePropertiesRequest)request);
-        }
-    }
-
-    /**
-     * Process a request that is composed of multiple other (non-composite) requests. If any of the embedded requests
-     * {@link Request#hasError() has an error} after it is processed, the submitted request will be marked with an error.
-     * <p>
-     * This method does nothing if the request is null.
-     * </p>
-     * 
-     * @param request the composite request
-     */
-    public void process( CompositeRequest request ) {
-        if (request == null) return;
-        int numberOfErrors = 0;
-        Throwable firstError = null;
-        for (Request embedded : request) {
-            assert embedded != null;
-            process(embedded);
-            if (embedded.hasError()) {
-                if (numberOfErrors == 0) firstError = embedded.getError();
-                ++numberOfErrors;
-            }
-        }
-        if (firstError == null) return;
-        if (numberOfErrors == 1) {
-            request.setError(firstError);
-        } else {
-            String msg = GraphI18n.multipleErrorsWhileExecutingRequests.text(numberOfErrors, request.size());
-            request.setError(new RepositorySourceException(getSourceName(), msg));
-        }
-    }
-
-    /**
-     * Process a request to copy a branch into another location.
-     * <p>
-     * This method does nothing if the request is null.
-     * </p>
-     * 
-     * @param request the copy request
-     */
-    public abstract void process( CopyBranchRequest request );
-
-    /**
-     * Process a request to create a node at a specified location.
-     * <p>
-     * This method does nothing if the request is null.
-     * </p>
-     * 
-     * @param request the create request
-     */
-    public abstract void process( CreateNodeRequest request );
-
-    /**
-     * Process a request to delete a branch at a specified location.
-     * <p>
-     * This method does nothing if the request is null.
-     * </p>
-     * 
-     * @param request the delete request
-     */
-    public abstract void process( DeleteBranchRequest request );
-
-    /**
-     * Process a request to move a branch at a specified location into a different location.
-     * <p>
-     * This method does nothing if the request is null.
-     * </p>
-     * 
-     * @param request the move request
-     */
-    public abstract void process( MoveBranchRequest request );
-
-    /**
-     * Process a request to read all of the children of a node.
-     * <p>
-     * This method does nothing if the request is null.
-     * </p>
-     * 
-     * @param request the read request
-     */
-    public abstract void process( ReadAllChildrenRequest request );
-
-    /**
-     * Process a request to read a block of the children of a node. The block is defined by a
-     * {@link ReadBlockOfChildrenRequest#startingAt() starting index} and a {@link ReadBlockOfChildrenRequest#count() maximum
-     * number of children to include in the block}.
-     * <p>
-     * This method does nothing if the request is null. The default implementation converts the command to a
-     * {@link ReadAllChildrenRequest}, and then finds the children within the block. Obviously for large numbers of children, this
-     * implementation may not be efficient and may need to be overridden.
-     * </p>
-     * 
-     * @param request the read request
-     */
-    public void process( ReadBlockOfChildrenRequest request ) {
-        if (request == null) return;
-        // Convert the request to a ReadAllChildrenRequest and execute it ...
-        ReadAllChildrenRequest readAll = new ReadAllChildrenRequest(request.of());
-        process(readAll);
-        if (readAll.hasError()) {
-            request.setError(readAll.getError());
-            return;
-        }
-        List<Location> allChildren = readAll.getChildren();
-
-        // If there aren't enough children for the block's range ...
-        if (allChildren.size() < request.startingAt()) return;
-
-        // Now, find the children in the block ...
-        int endIndex = Math.min(request.endingBefore(), allChildren.size());
-        for (int i = request.startingAt(); i != endIndex; ++i) {
-            request.addChild(allChildren.get(i));
-        }
-    }
-
-    /**
-     * Process a request to read a branch or subgraph that's below a node at a specified location.
-     * <p>
-     * This method does nothing if the request is null. The default implementation processes the branch by submitting the
-     * equivalent requests to {@link ReadNodeRequest read the nodes} and the {@link ReadAllChildrenRequest children}. It starts by
-     * doing this for the top-level node, then proceeds for each of the children of that node, and so forth.
-     * </p>
-     * 
-     * @param request the request to read the branch
-     */
-    public void process( ReadBranchRequest request ) {
-        if (request == null) return;
-        // Create a queue for locations that need to be read ...
-        Queue<LocationWithDepth> locationsToRead = new LinkedList<LocationWithDepth>();
-        locationsToRead.add(new LocationWithDepth(request.at(), 1));
-
-        // Now read the locations ...
-        while (locationsToRead.peek() != null) {
-            LocationWithDepth read = locationsToRead.poll();
-
-            // Check the depth ...
-            if (read.depth > request.maximumDepth()) break;
-
-            // Read the properties ...
-            ReadNodeRequest readNode = new ReadNodeRequest(read.location);
-            process(readNode);
-            if (readNode.hasError()) {
-                request.setError(readNode.getError());
-                return;
-            }
-            request.setProperties(read.location, readNode.getProperties());
-
-            // Read the children for this node, and add them to the list of locations to be read ...
-            ReadAllChildrenRequest readChildren = new ReadAllChildrenRequest(read.location);
-            process(readChildren);
-            request.setChildren(read.location, readChildren.getChildren());
-
-            // Add each of the children to the list of locations that we need to read ...
-            for (Location child : readChildren) {
-                locationsToRead.add(new LocationWithDepth(child, read.depth + 1));
-            }
-        }
-    }
-
-    /**
-     * Process a request to read the properties of a node at the supplied location.
-     * <p>
-     * This method does nothing if the request is null.
-     * </p>
-     * 
-     * @param request the read request
-     */
-    public abstract void process( ReadAllPropertiesRequest request );
-
-    /**
-     * Process a request to read the properties and children of a node at the supplied location.
-     * <p>
-     * This method does nothing if the request is null. Unless overridden, this method converts the single request into a
-     * {@link ReadAllChildrenRequest} and a {@link ReadAllPropertiesRequest}.
-     * </p>
-     * 
-     * @param request the read request
-     */
-    public void process( ReadNodeRequest request ) {
-        if (request == null) return;
-        // Read the properties ...
-        ReadAllPropertiesRequest readProperties = new ReadAllPropertiesRequest(request.at());
-        process(readProperties);
-        if (readProperties.hasError()) {
-            request.setError(readProperties.getError());
-            return;
-        }
-        // Read the children ...
-        ReadAllChildrenRequest readChildren = new ReadAllChildrenRequest(request.at());
-        process(readChildren);
-        if (readChildren.hasError()) {
-            request.setError(readChildren.getError());
-            return;
-        }
-        // Now, copy all of the results into the submitted request ...
-        for (Property property : readProperties) {
-            request.addProperty(property);
-        }
-        for (Location child : readChildren) {
-            request.addChild(child);
-        }
-    }
-
-    /**
-     * Process a request to read a single property of a node at the supplied location.
-     * <p>
-     * This method does nothing if the request is null. Unless overridden, this method converts the request that
-     * {@link ReadNodeRequest reads the node} and simply returns the one property.
-     * </p>
-     * 
-     * @param request the read request
-     */
-    public void process( ReadPropertyRequest request ) {
-        if (request == null) return;
-        ReadNodeRequest readNode = new ReadNodeRequest(request.on());
-        process(readNode);
-        if (readNode.hasError()) {
-            request.setError(readNode.getError());
-            return;
-        }
-        Property property = readNode.getPropertiesByName().get(request.named());
-        request.setProperty(property);
-    }
-
-    /**
-     * Process a request to remove the specified properties from a node.
-     * <p>
-     * This method does nothing if the request is null. Unless overridden, this method converts this request into a
-     * {@link UpdatePropertiesRequest}.
-     * </p>
-     * 
-     * @param request the request to remove the properties with certain names
-     */
-    public void process( RemovePropertiesRequest request ) {
-        if (request == null) return;
-        Collection<Name> names = request.propertyNames();
-        if (names.isEmpty()) return;
-        List<Property> emptyProperties = new ArrayList<Property>(names.size());
-        for (Name propertyName : names) {
-            emptyProperties.add(new BasicEmptyProperty(propertyName));
-        }
-        UpdatePropertiesRequest update = new UpdatePropertiesRequest(request.from(), emptyProperties);
-        process(update);
-        if (update.hasError()) {
-            request.setError(update.getError());
-        }
-    }
-
-    /**
-     * Process a request to remove the specified properties from a node.
-     * <p>
-     * This method does nothing if the request is null.
-     * </p>
-     * 
-     * @param request the remove request
-     */
-    public abstract void process( UpdatePropertiesRequest request );
-
-    /**
-     * Process a request to rename a node specified location into a different location.
-     * <p>
-     * This method does nothing if the request is null. Unless overridden, this method converts the rename into a
-     * {@link MoveBranchRequest move}. However, this only works if the <code>request</code> has a {@link Location#hasPath() path}
-     * for its {@link RenameNodeRequest#at() location}. (If not, this method throws an {@link UnsupportedOperationException} and
-     * must be overriddent.)
-     * </p>
-     * 
-     * @param request the rename request
-     */
-    public void process( RenameNodeRequest request ) {
-        if (request == null) return;
-        Location from = request.at();
-        if (!from.hasPath()) {
-            throw new UnsupportedOperationException();
-        }
-        Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(from.getPath(), request.toName());
-        Location to = new Location(newPath);
-        MoveBranchRequest move = new MoveBranchRequest(from, to);
-        process(move);
-    }
-
-    /**
-     * A class that represents a location at a known depth
-     * 
-     * @author Randall Hauch
-     */
-    protected static class LocationWithDepth {
-        protected final Location location;
-        protected final int depth;
-
-        protected LocationWithDepth( Location location,
-                                     int depth ) {
-            this.location = location;
-            this.depth = depth;
-        }
-
-        @Override
-        public String toString() {
-            return location.toString() + " at depth " + depth;
-        }
-    }
-
-}

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/UpdatePropertiesRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/UpdatePropertiesRequest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/UpdatePropertiesRequest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -29,6 +29,7 @@
 import java.util.List;
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.GraphI18n;
 import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.Property;
 
@@ -39,8 +40,11 @@
  */
 public class UpdatePropertiesRequest extends Request implements Iterable<Property> {
 
+    private static final long serialVersionUID = 1L;
+
     private final Location on;
     private final List<Property> properties;
+    private Location actualLocation;
 
     /**
      * Create a request to update the properties on the node at the supplied location.
@@ -97,6 +101,16 @@
     }
 
     /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.Request#isReadOnly()
+     */
+    @Override
+    public boolean isReadOnly() {
+        return false;
+    }
+
+    /**
      * Get the location defining the node that is to be updated.
      * 
      * @return the location of the node; never null
@@ -124,6 +138,34 @@
     }
 
     /**
+     * Sets the actual and complete location of the node being updated. This method must be called when processing the request,
+     * and the actual location must have a {@link Location#getPath() path}.
+     * 
+     * @param actual the actual location of the node being updated, or null if the {@link #on() current location} should be used
+     * @throws IllegalArgumentException if the actual location does represent the {@link Location#isSame(Location) same location}
+     *         as the {@link #on() current location}, or if the actual location does not have a path.
+     */
+    public void setActualLocationOfNode( Location actual ) {
+        if (!on.isSame(actual)) { // not same if actual is null
+            throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actual, on));
+        }
+        assert actual != null;
+        if (!actual.hasPath()) {
+            throw new IllegalArgumentException(GraphI18n.actualLocationMustHavePath.text(actual));
+        }
+        this.actualLocation = actual;
+    }
+
+    /**
+     * Get the actual location of the node that was updated.
+     * 
+     * @return the actual location, or null if the actual location was not set
+     */
+    public Location getActualLocationOfNode() {
+        return actualLocation;
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#equals(java.lang.Object)

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/processor/LoggingRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/processor/LoggingRequestProcessor.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/processor/LoggingRequestProcessor.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -0,0 +1,261 @@
+/*
+ * 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.graph.requests.processor;
+
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.Logger;
+import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.requests.CompositeRequest;
+import org.jboss.dna.graph.requests.CopyBranchRequest;
+import org.jboss.dna.graph.requests.CreateNodeRequest;
+import org.jboss.dna.graph.requests.DeleteBranchRequest;
+import org.jboss.dna.graph.requests.MoveBranchRequest;
+import org.jboss.dna.graph.requests.ReadAllChildrenRequest;
+import org.jboss.dna.graph.requests.ReadAllPropertiesRequest;
+import org.jboss.dna.graph.requests.ReadBlockOfChildrenRequest;
+import org.jboss.dna.graph.requests.ReadBranchRequest;
+import org.jboss.dna.graph.requests.ReadNodeRequest;
+import org.jboss.dna.graph.requests.ReadPropertyRequest;
+import org.jboss.dna.graph.requests.RemovePropertiesRequest;
+import org.jboss.dna.graph.requests.RenameNodeRequest;
+import org.jboss.dna.graph.requests.Request;
+import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
+
+/**
+ * A {@link RequestProcessor} implementation that wraps another and that logs messages at the supplied level.
+ * 
+ * @author Randall Hauch
+ */
+public class LoggingRequestProcessor extends RequestProcessor {
+
+    private final RequestProcessor delegate;
+    private final Logger logger;
+    private final Logger.Level level;
+
+    /**
+     * @param delegate the processor to which this processor delegates
+     * @param logger the logger that should be used
+     * @param level the level of the log messages; defaults to {@link Logger.Level#TRACE}
+     */
+    public LoggingRequestProcessor( RequestProcessor delegate,
+                                    Logger logger,
+                                    Logger.Level level ) {
+        super(delegate.getSourceName(), delegate.getExecutionContext());
+        CheckArg.isNotNull(logger, "logger");
+        this.delegate = delegate;
+        this.logger = logger;
+        this.level = level != null ? level : Logger.Level.TRACE;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CopyBranchRequest)
+     */
+    @Override
+    public void process( CopyBranchRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CreateNodeRequest)
+     */
+    @Override
+    public void process( CreateNodeRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.DeleteBranchRequest)
+     */
+    @Override
+    public void process( DeleteBranchRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.MoveBranchRequest)
+     */
+    @Override
+    public void process( MoveBranchRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadAllChildrenRequest)
+     */
+    @Override
+    public void process( ReadAllChildrenRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadAllPropertiesRequest)
+     */
+    @Override
+    public void process( ReadAllPropertiesRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.UpdatePropertiesRequest)
+     */
+    @Override
+    public void process( UpdatePropertiesRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CompositeRequest)
+     */
+    @Override
+    public void process( CompositeRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadBlockOfChildrenRequest)
+     */
+    @Override
+    public void process( ReadBlockOfChildrenRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadBranchRequest)
+     */
+    @Override
+    public void process( ReadBranchRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadNodeRequest)
+     */
+    @Override
+    public void process( ReadNodeRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadPropertyRequest)
+     */
+    @Override
+    public void process( ReadPropertyRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.RemovePropertiesRequest)
+     */
+    @Override
+    public void process( RemovePropertiesRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.RenameNodeRequest)
+     */
+    @Override
+    public void process( RenameNodeRequest request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.Request)
+     */
+    @Override
+    public void process( Request request ) {
+        logger.log(level, GraphI18n.executingRequest, request);
+        delegate.process(request);
+        logger.log(level, GraphI18n.executedRequest, request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#close()
+     */
+    @Override
+    public void close() {
+        logger.log(level, GraphI18n.closingRequestProcessor);
+        delegate.close();
+        logger.log(level, GraphI18n.closingRequestProcessor);
+    }
+
+}


Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/processor/LoggingRequestProcessor.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Copied: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/processor/RequestProcessor.java (from rev 567, trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/RequestProcessor.java)
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/processor/RequestProcessor.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/processor/RequestProcessor.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -0,0 +1,483 @@
+/*
+ * 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.graph.requests.processor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connectors.RepositorySourceException;
+import org.jboss.dna.graph.properties.DateTime;
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.Path;
+import org.jboss.dna.graph.properties.Property;
+import org.jboss.dna.graph.properties.basic.BasicEmptyProperty;
+import org.jboss.dna.graph.requests.CompositeRequest;
+import org.jboss.dna.graph.requests.CopyBranchRequest;
+import org.jboss.dna.graph.requests.CreateNodeRequest;
+import org.jboss.dna.graph.requests.DeleteBranchRequest;
+import org.jboss.dna.graph.requests.MoveBranchRequest;
+import org.jboss.dna.graph.requests.ReadAllChildrenRequest;
+import org.jboss.dna.graph.requests.ReadAllPropertiesRequest;
+import org.jboss.dna.graph.requests.ReadBlockOfChildrenRequest;
+import org.jboss.dna.graph.requests.ReadBranchRequest;
+import org.jboss.dna.graph.requests.ReadNodeRequest;
+import org.jboss.dna.graph.requests.ReadPropertyRequest;
+import org.jboss.dna.graph.requests.RemovePropertiesRequest;
+import org.jboss.dna.graph.requests.RenameNodeRequest;
+import org.jboss.dna.graph.requests.Request;
+import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
+
+/**
+ * A component that is used to process and execute {@link Request}s. This class is intended to be subclassed and methods
+ * overwritten to define the behavior for executing the different kinds of requests. Abstract methods must be overridden, but
+ * non-abstract methods all have meaningful default implementations.
+ * 
+ * @author Randall Hauch
+ */
+ at Immutable
+public abstract class RequestProcessor {
+
+    private final ExecutionContext context;
+    private final String sourceName;
+    private final DateTime nowInUtc;
+
+    protected RequestProcessor( String sourceName,
+                                ExecutionContext context ) {
+        this(sourceName, context, null);
+    }
+
+    protected RequestProcessor( String sourceName,
+                                ExecutionContext context,
+                                DateTime now ) {
+        CheckArg.isNotEmpty(sourceName, "sourceName");
+        CheckArg.isNotNull(context, "context");
+        this.context = context;
+        this.sourceName = sourceName;
+        this.nowInUtc = now != null ? now : context.getValueFactories().getDateFactory().createUtc();
+    }
+
+    /**
+     * Get the name of the source against which this processor is executing.
+     * 
+     * @return the repository source name; never null or empty
+     */
+    public String getSourceName() {
+        return sourceName;
+    }
+
+    /**
+     * The execution context that this process is operating within.
+     * 
+     * @return the execution context; never null
+     */
+    public ExecutionContext getExecutionContext() {
+        return this.context;
+    }
+
+    /**
+     * Get the 'current time' for this processor, which is usually a constant during its lifetime.
+     * 
+     * @return the current time in UTC; never null
+     */
+    protected DateTime getNowInUtc() {
+        return this.nowInUtc;
+    }
+
+    /**
+     * Process a request by determining the type of request and delegating to the appropriate <code>process</code> method for that
+     * type.
+     * <p>
+     * This method does nothing if the request is null.
+     * </p>
+     * 
+     * @param request the general request
+     */
+    public void process( Request request ) {
+        if (request == null) return;
+        if (request instanceof CompositeRequest) {
+            process((CompositeRequest)request);
+        } else if (request instanceof CopyBranchRequest) {
+            process((CopyBranchRequest)request);
+        } else if (request instanceof CreateNodeRequest) {
+            process((CreateNodeRequest)request);
+        } else if (request instanceof DeleteBranchRequest) {
+            process((DeleteBranchRequest)request);
+        } else if (request instanceof MoveBranchRequest) {
+            process((MoveBranchRequest)request);
+        } else if (request instanceof ReadAllChildrenRequest) {
+            process((ReadAllChildrenRequest)request);
+        } else if (request instanceof ReadBlockOfChildrenRequest) {
+            process((ReadBlockOfChildrenRequest)request);
+        } else if (request instanceof ReadBranchRequest) {
+            process((ReadBranchRequest)request);
+        } else if (request instanceof ReadNodeRequest) {
+            process((ReadNodeRequest)request);
+        } else if (request instanceof ReadAllPropertiesRequest) {
+            process((ReadAllPropertiesRequest)request);
+        } else if (request instanceof ReadPropertyRequest) {
+            process((ReadPropertyRequest)request);
+        } else if (request instanceof RemovePropertiesRequest) {
+            process((RemovePropertiesRequest)request);
+        } else if (request instanceof RenameNodeRequest) {
+            process((RenameNodeRequest)request);
+        } else if (request instanceof UpdatePropertiesRequest) {
+            process((UpdatePropertiesRequest)request);
+        }
+    }
+
+    /**
+     * Process a request that is composed of multiple other (non-composite) requests. If any of the embedded requests
+     * {@link Request#hasError() has an error} after it is processed, the submitted request will be marked with an error.
+     * <p>
+     * This method does nothing if the request is null.
+     * </p>
+     * 
+     * @param request the composite request
+     */
+    public void process( CompositeRequest request ) {
+        if (request == null) return;
+        int numberOfErrors = 0;
+        Throwable firstError = null;
+        for (Request embedded : request) {
+            assert embedded != null;
+            process(embedded);
+            if (embedded.hasError()) {
+                if (numberOfErrors == 0) firstError = embedded.getError();
+                ++numberOfErrors;
+            }
+        }
+        if (firstError == null) return;
+        if (numberOfErrors == 1) {
+            request.setError(firstError);
+        } else {
+            String msg = GraphI18n.multipleErrorsWhileExecutingRequests.text(numberOfErrors, request.size());
+            request.setError(new RepositorySourceException(getSourceName(), msg));
+        }
+    }
+
+    /**
+     * Process a request to copy a branch into another location.
+     * <p>
+     * This method does nothing if the request is null.
+     * </p>
+     * 
+     * @param request the copy request
+     */
+    public abstract void process( CopyBranchRequest request );
+
+    /**
+     * Process a request to create a node at a specified location.
+     * <p>
+     * This method does nothing if the request is null.
+     * </p>
+     * 
+     * @param request the create request
+     */
+    public abstract void process( CreateNodeRequest request );
+
+    /**
+     * Process a request to delete a branch at a specified location.
+     * <p>
+     * This method does nothing if the request is null.
+     * </p>
+     * 
+     * @param request the delete request
+     */
+    public abstract void process( DeleteBranchRequest request );
+
+    /**
+     * Process a request to move a branch at a specified location into a different location.
+     * <p>
+     * This method does nothing if the request is null.
+     * </p>
+     * 
+     * @param request the move request
+     */
+    public abstract void process( MoveBranchRequest request );
+
+    /**
+     * Process a request to read all of the children of a node.
+     * <p>
+     * This method does nothing if the request is null.
+     * </p>
+     * 
+     * @param request the read request
+     */
+    public abstract void process( ReadAllChildrenRequest request );
+
+    /**
+     * Process a request to read a block of the children of a node. The block is defined by a
+     * {@link ReadBlockOfChildrenRequest#startingAt() starting index} and a {@link ReadBlockOfChildrenRequest#count() maximum
+     * number of children to include in the block}.
+     * <p>
+     * This method does nothing if the request is null. The default implementation converts the command to a
+     * {@link ReadAllChildrenRequest}, and then finds the children within the block. Obviously for large numbers of children, this
+     * implementation may not be efficient and may need to be overridden.
+     * </p>
+     * 
+     * @param request the read request
+     */
+    public void process( ReadBlockOfChildrenRequest request ) {
+        if (request == null) return;
+        // Convert the request to a ReadAllChildrenRequest and execute it ...
+        ReadAllChildrenRequest readAll = new ReadAllChildrenRequest(request.of());
+        process(readAll);
+        if (readAll.hasError()) {
+            request.setError(readAll.getError());
+            return;
+        }
+        List<Location> allChildren = readAll.getChildren();
+
+        // If there aren't enough children for the block's range ...
+        if (allChildren.size() < request.startingAt()) return;
+
+        // Now, find the children in the block ...
+        int endIndex = Math.min(request.endingBefore(), allChildren.size());
+        for (int i = request.startingAt(); i != endIndex; ++i) {
+            request.addChild(allChildren.get(i));
+        }
+        // Set the actual location ...
+        request.setActualLocationOfNode(readAll.getActualLocationOfNode());
+    }
+
+    /**
+     * Process a request to read a branch or subgraph that's below a node at a specified location.
+     * <p>
+     * This method does nothing if the request is null. The default implementation processes the branch by submitting the
+     * equivalent requests to {@link ReadNodeRequest read the nodes} and the {@link ReadAllChildrenRequest children}. It starts by
+     * doing this for the top-level node, then proceeds for each of the children of that node, and so forth.
+     * </p>
+     * 
+     * @param request the request to read the branch
+     */
+    public void process( ReadBranchRequest request ) {
+        if (request == null) return;
+        // Create a queue for locations that need to be read ...
+        Queue<LocationWithDepth> locationsToRead = new LinkedList<LocationWithDepth>();
+        locationsToRead.add(new LocationWithDepth(request.at(), 1));
+
+        // Now read the locations ...
+        boolean first = true;
+        while (locationsToRead.peek() != null) {
+            LocationWithDepth read = locationsToRead.poll();
+
+            // Check the depth ...
+            if (read.depth > request.maximumDepth()) break;
+
+            // Read the properties ...
+            ReadNodeRequest readNode = new ReadNodeRequest(read.location);
+            process(readNode);
+            if (readNode.hasError()) {
+                request.setError(readNode.getError());
+                return;
+            }
+            Location actualLocation = readNode.getActualLocationOfNode();
+            if (first) {
+                // Set the actual location on the original request
+                request.setActualLocationOfNode(actualLocation);
+                first = false;
+            }
+
+            // Record in the request the children and properties that were read on this node ...
+            request.setChildren(actualLocation, readNode.getChildren());
+            request.setProperties(actualLocation, readNode.getProperties());
+
+            // Add each of the children to the list of locations that we need to read ...
+            for (Location child : readNode.getChildren()) {
+                locationsToRead.add(new LocationWithDepth(child, read.depth + 1));
+            }
+        }
+    }
+
+    /**
+     * Process a request to read the properties of a node at the supplied location.
+     * <p>
+     * This method does nothing if the request is null.
+     * </p>
+     * 
+     * @param request the read request
+     */
+    public abstract void process( ReadAllPropertiesRequest request );
+
+    /**
+     * Process a request to read the properties and children of a node at the supplied location.
+     * <p>
+     * This method does nothing if the request is null. Unless overridden, this method converts the single request into a
+     * {@link ReadAllChildrenRequest} and a {@link ReadAllPropertiesRequest}.
+     * </p>
+     * 
+     * @param request the read request
+     */
+    public void process( ReadNodeRequest request ) {
+        if (request == null) return;
+        // Read the properties ...
+        ReadAllPropertiesRequest readProperties = new ReadAllPropertiesRequest(request.at());
+        process(readProperties);
+        if (readProperties.hasError()) {
+            request.setError(readProperties.getError());
+            return;
+        }
+        // Set the actual location ...
+        request.setActualLocationOfNode(readProperties.getActualLocationOfNode());
+
+        // Read the children ...
+        ReadAllChildrenRequest readChildren = new ReadAllChildrenRequest(request.at());
+        process(readChildren);
+        if (readChildren.hasError()) {
+            request.setError(readChildren.getError());
+            return;
+        }
+        // Now, copy all of the results into the submitted request ...
+        for (Property property : readProperties) {
+            request.addProperty(property);
+        }
+        for (Location child : readChildren) {
+            request.addChild(child);
+        }
+    }
+
+    /**
+     * Process a request to read a single property of a node at the supplied location.
+     * <p>
+     * This method does nothing if the request is null. Unless overridden, this method converts the request that
+     * {@link ReadNodeRequest reads the node} and simply returns the one property.
+     * </p>
+     * 
+     * @param request the read request
+     */
+    public void process( ReadPropertyRequest request ) {
+        if (request == null) return;
+        ReadAllPropertiesRequest readNode = new ReadAllPropertiesRequest(request.on());
+        process(readNode);
+        if (readNode.hasError()) {
+            request.setError(readNode.getError());
+            return;
+        }
+        Property property = readNode.getPropertiesByName().get(request.named());
+        request.setProperty(property);
+        // Set the actual location ...
+        request.setActualLocationOfNode(readNode.getActualLocationOfNode());
+    }
+
+    /**
+     * Process a request to remove the specified properties from a node.
+     * <p>
+     * This method does nothing if the request is null. Unless overridden, this method converts this request into a
+     * {@link UpdatePropertiesRequest}.
+     * </p>
+     * 
+     * @param request the request to remove the properties with certain names
+     */
+    public void process( RemovePropertiesRequest request ) {
+        if (request == null) return;
+        Collection<Name> names = request.propertyNames();
+        if (names.isEmpty()) return;
+        List<Property> emptyProperties = new ArrayList<Property>(names.size());
+        for (Name propertyName : names) {
+            emptyProperties.add(new BasicEmptyProperty(propertyName));
+        }
+        UpdatePropertiesRequest update = new UpdatePropertiesRequest(request.from(), emptyProperties);
+        process(update);
+        if (update.hasError()) {
+            request.setError(update.getError());
+        }
+        // Set the actual location ...
+        request.setActualLocationOfNode(update.getActualLocationOfNode());
+    }
+
+    /**
+     * Process a request to remove the specified properties from a node.
+     * <p>
+     * This method does nothing if the request is null.
+     * </p>
+     * 
+     * @param request the remove request
+     */
+    public abstract void process( UpdatePropertiesRequest request );
+
+    /**
+     * Process a request to rename a node specified location into a different location.
+     * <p>
+     * This method does nothing if the request is null. Unless overridden, this method converts the rename into a
+     * {@link MoveBranchRequest move}. However, this only works if the <code>request</code> has a {@link Location#hasPath() path}
+     * for its {@link RenameNodeRequest#at() location}. (If not, this method throws an {@link UnsupportedOperationException} and
+     * must be overriddent.)
+     * </p>
+     * 
+     * @param request the rename request
+     */
+    public void process( RenameNodeRequest request ) {
+        if (request == null) return;
+        Location from = request.at();
+        if (!from.hasPath()) {
+            throw new UnsupportedOperationException();
+        }
+        Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(from.getPath(), request.toName());
+        Location to = new Location(newPath);
+        MoveBranchRequest move = new MoveBranchRequest(from, to);
+        process(move);
+        // Set the actual locations ...
+        request.setActualLocations(move.getActualLocationBefore(), move.getActualLocationAfter());
+    }
+
+    /**
+     * Close this processor, allowing it to clean up any open resources.
+     */
+    public void close() {
+        // do nothing
+    }
+
+    /**
+     * A class that represents a location at a known depth
+     * 
+     * @author Randall Hauch
+     */
+    @Immutable
+    protected static class LocationWithDepth {
+        protected final Location location;
+        protected final int depth;
+
+        protected LocationWithDepth( Location location,
+                                     int depth ) {
+            this.location = location;
+            this.depth = depth;
+        }
+
+        @Override
+        public int hashCode() {
+            return location.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return location.toString() + " at depth " + depth;
+        }
+    }
+
+}


Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/requests/processor/RequestProcessor.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/util/GraphImporter.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/util/GraphImporter.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/util/GraphImporter.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -21,34 +21,23 @@
  */
 package org.jboss.dna.graph.util;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import java.util.LinkedList;
 import java.util.Set;
-import net.jcip.annotations.Immutable;
 import org.jboss.dna.common.i18n.I18n;
 import org.jboss.dna.common.monitor.ProgressMonitor;
 import org.jboss.dna.common.monitor.SimpleProgressMonitor;
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.common.util.Logger;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
 import org.jboss.dna.graph.GraphI18n;
-import org.jboss.dna.graph.commands.CompositeCommand;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.commands.NodeConflictBehavior;
-import org.jboss.dna.graph.commands.basic.BasicCreateNodeCommand;
-import org.jboss.dna.graph.commands.basic.BasicGraphCommand;
-import org.jboss.dna.graph.connectors.RepositoryConnection;
-import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.NodeConflictBehavior;
 import org.jboss.dna.graph.connectors.RepositorySource;
 import org.jboss.dna.graph.connectors.RepositorySourceException;
 import org.jboss.dna.graph.properties.Name;
@@ -73,185 +62,51 @@
  */
 public class GraphImporter {
 
-    public interface ImportSpecification {
-        /**
-         * Specify the location where the content is to be imported, and then perform the import. This is equivalent to calling
-         * <code>{@link #into(String, Path) into(sourceName,rootPath)}</code>.
-         * 
-         * @param sourceName the name of the source into which the content is to be imported
-         * @throws IllegalArgumentException if the <code>uri</code> or path are null
-         * @throws IOException if there is a problem reading the content
-         * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource
-         *         repository source}
-         */
-        void into( String sourceName ) throws IOException, RepositorySourceException;
+    private final Graph graph;
 
-        /**
-         * Specify the location where the content is to be imported, and then perform the import.
-         * 
-         * @param sourceName the name of the source into which the content is to be imported
-         * @param pathInSource the path in the {@link RepositorySource repository source} named <code>sourceName</code> where the
-         *        content is to be written; may not be null
-         * @throws IllegalArgumentException if the <code>uri</code> or path are null
-         * @throws IOException if there is a problem reading the content
-         * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource
-         *         repository source}
-         */
-        void into( String sourceName,
-                   Path pathInSource ) throws IOException, RepositorySourceException;
+    public GraphImporter( Graph graph ) {
+        CheckArg.isNotNull(graph, "graph");
+        this.graph = graph;
     }
 
-    @Immutable
-    protected abstract class ImportedContentUsingSequencer implements ImportSpecification {
-        private final StreamSequencer sequencer;
-
-        protected ImportedContentUsingSequencer( StreamSequencer sequencer ) {
-            this.sequencer = sequencer;
-        }
-
-        protected StreamSequencer getSequencer() {
-            return this.sequencer;
-        }
-
-        protected NodeConflictBehavior getConflictBehavior() {
-            return NodeConflictBehavior.UPDATE;
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see org.jboss.dna.graph.util.GraphImporter.ImportSpecification#into(java.lang.String)
-         */
-        public void into( String sourceName ) throws IOException, RepositorySourceException {
-            Path root = getContext().getValueFactories().getPathFactory().createRootPath();
-            into(sourceName, root);
-        }
-    }
-
-    @Immutable
-    protected class UriImportedContent extends ImportedContentUsingSequencer {
-        private final URI uri;
-        private final String mimeType;
-
-        protected UriImportedContent( StreamSequencer sequencer,
-                                      URI uri,
-                                      String mimeType ) {
-            super(sequencer);
-            this.uri = uri;
-            this.mimeType = mimeType;
-        }
-
-        /**
-         * @return mimeType
-         */
-        public String getMimeType() {
-            return mimeType;
-        }
-
-        /**
-         * @return uri
-         */
-        public URI getUri() {
-            return uri;
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see org.jboss.dna.graph.util.GraphImporter.ImportSpecification#into(java.lang.String,
-         *      org.jboss.dna.graph.properties.Path)
-         */
-        public void into( String sourceName,
-                          Path pathInSource ) throws IOException, RepositorySourceException {
-            CheckArg.isNotNull(sourceName, "sourceName");
-            CheckArg.isNotNull(pathInSource, "pathInSource");
-            importWithSequencer(getSequencer(), uri, mimeType, sourceName, pathInSource, getConflictBehavior());
-        }
-    }
-
-    private final RepositoryConnectionFactory sources;
-    private final ExecutionContext context;
-
-    public GraphImporter( RepositoryConnectionFactory sources,
-                          ExecutionContext context ) {
-        CheckArg.isNotNull(sources, "sources");
-        CheckArg.isNotNull(context, "context");
-        this.sources = sources;
-        this.context = context;
-    }
-
     /**
      * Get the context in which the importer will be executed.
      * 
      * @return the execution context; never null
      */
     public ExecutionContext getContext() {
-        return this.context;
+        return this.graph.getContext();
     }
 
     /**
-     * Import the content from the XML file at the supplied URI, specifying on the returned {@link ImportSpecification} where the
-     * content is to be imported.
+     * The graph that this importer uses.
      * 
-     * @param uri the URI where the importer can read the content that is to be imported
-     * @return the object that should be used to specify into which the content is to be imported
-     * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
+     * @return the graph; never null
      */
-    public ImportSpecification importXml( URI uri ) {
-        CheckArg.isNotNull(uri, "uri");
-
-        // Create the sequencer ...
-        StreamSequencer sequencer = new XmlSequencer();
-        return new UriImportedContent(sequencer, uri, "text/xml");
+    public Graph getGraph() {
+        return graph;
     }
 
     /**
-     * Import the content from the XML file at the supplied file location, specifying on the returned {@link ImportSpecification}
-     * where the content is to be imported.
-     * 
-     * @param pathToFile the path to the XML file that should be imported.
-     * @return the object that should be used to specify into which the content is to be imported
-     * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
-     */
-    public ImportSpecification importXml( String pathToFile ) {
-        CheckArg.isNotNull(pathToFile, "pathToFile");
-        return importXml(new File(pathToFile).toURI());
-    }
-
-    /**
-     * Import the content from the supplied XML file, specifying on the returned {@link ImportSpecification} where the content is
-     * to be imported.
-     * 
-     * @param file the XML file that should be imported.
-     * @return the object that should be used to specify into which the content is to be imported
-     * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
-     */
-    public ImportSpecification importXml( File file ) {
-        CheckArg.isNotNull(file, "file");
-        return importXml(file.toURI());
-    }
-
-    /**
      * Read the content from the supplied URI and import into the repository at the supplied location.
      * 
      * @param uri the URI where the importer can read the content that is to be imported
-     * @param sourceName the name of the source into which the content is to be imported
-     * @param destinationPathInSource the path in the {@link RepositorySource repository source} where the content is to be
-     *        written; may not be null
+     * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+     *        be null
+     * @return the batch of requests for creating the graph content that represents the imported content
      * @throws IllegalArgumentException if the <code>uri</code> or destination path are null
      * @throws IOException if there is a problem reading the content
      * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
      *         source}
      */
-    public void importXml( URI uri,
-                           String sourceName,
-                           Path destinationPathInSource ) throws IOException, RepositorySourceException {
+    public Graph.Batch importXml( URI uri,
+                                  Location location ) throws IOException, RepositorySourceException {
         CheckArg.isNotNull(uri, "uri");
-        CheckArg.isNotNull(destinationPathInSource, "destinationPathInSource");
+        CheckArg.isNotNull(location, "location");
 
         // Create the sequencer ...
         StreamSequencer sequencer = new XmlSequencer();
-        importWithSequencer(sequencer, uri, "text/xml", sourceName, destinationPathInSource, NodeConflictBehavior.UPDATE);
+        return importWithSequencer(sequencer, uri, "text/xml", location, NodeConflictBehavior.UPDATE);
     }
 
     /**
@@ -261,26 +116,25 @@
      * @param sequencer the sequencer that should be used; may not be null
      * @param contentUri the URI where the content can be found; may not be null
      * @param mimeType the MIME type for the content; may not be null
-     * @param sourceName the name of the source into which the content is to be imported
-     * @param destinationPathInSource the path in the {@link RepositorySource repository source} where the content is to be
-     *        written; may not be null
+     * @param location the location in the {@link RepositorySource repository source} where the content is to be written; may not
+     *        be null
      * @param conflictBehavior the behavior when a node is to be created when an existing node already exists; defaults to
      *        {@link NodeConflictBehavior#UPDATE} if null
+     * @return the batch of requests for creating the graph content that represents the imported content
      * @throws IOException if there is a problem reading the content
      * @throws RepositorySourceException if there is a problem while writing the content to the {@link RepositorySource repository
      *         source}
      */
-    protected void importWithSequencer( StreamSequencer sequencer,
-                                        URI contentUri,
-                                        String mimeType,
-                                        String sourceName,
-                                        Path destinationPathInSource,
-                                        NodeConflictBehavior conflictBehavior ) throws IOException, RepositorySourceException {
+    protected Graph.Batch importWithSequencer( StreamSequencer sequencer,
+                                               URI contentUri,
+                                               String mimeType,
+                                               Location location,
+                                               NodeConflictBehavior conflictBehavior )
+        throws IOException, RepositorySourceException {
         assert sequencer != null;
         assert contentUri != null;
         assert mimeType != null;
-        assert sourceName != null;
-        assert destinationPathInSource != null;
+        assert location != null;
         conflictBehavior = conflictBehavior != null ? conflictBehavior : NodeConflictBehavior.UPDATE;
 
         // Get the input path by creating from the URI, in case the URI is a valid path ...
@@ -295,13 +149,14 @@
         ImporterContext importerContext = new ImporterContext(inputPath, inputProperties, "text/xml");
 
         // Now run the sequencer ...
-        String activity = GraphI18n.errorImportingContent.text(destinationPathInSource, contentUri);
+        String activity = GraphI18n.errorImportingContent.text(location.getPath(), contentUri);
         ProgressMonitor progressMonitor = new SimpleProgressMonitor(activity);
-        ImporterCommands commands = new ImporterCommands(destinationPathInSource, conflictBehavior);
+        Graph.Batch batch = getGraph().batch();
+        ImporterOutput importedContent = new ImporterOutput(batch, location.getPath());
         InputStream stream = null;
         try {
             stream = contentUri.toURL().openStream();
-            sequencer.sequence(stream, commands, importerContext, progressMonitor);
+            sequencer.sequence(stream, importedContent, importerContext, progressMonitor);
         } catch (MalformedURLException err) {
             throw new IOException(err.getMessage());
         } finally {
@@ -310,30 +165,15 @@
                     stream.close();
                 } catch (IOException e) {
                     I18n msg = GraphI18n.errorImportingContent;
-                    context.getLogger(getClass()).error(e, msg, mimeType, contentUri);
+                    getContext().getLogger(getClass()).error(e, msg, mimeType, contentUri);
                 }
             }
         }
+        // Finish any leftovers ...
+        importedContent.process();
 
         // Now execute the commands against the repository ...
-        RepositoryConnection connection = null;
-        try {
-            connection = sources.createConnection(sourceName);
-            if (connection == null) {
-                I18n msg = GraphI18n.unableToFindRepositorySourceWithName;
-                throw new RepositorySourceException(msg.text(sourceName));
-            }
-            connection.execute(context, commands);
-        } finally {
-            if (connection != null) {
-                try {
-                    connection.close();
-                } catch (RepositorySourceException e) {
-                    I18n msg = GraphI18n.errorImportingContent;
-                    context.getLogger(getClass()).error(e, msg, mimeType, contentUri);
-                }
-            }
-        }
+        return batch;
     }
 
     /**
@@ -350,40 +190,19 @@
         }
     }
 
-    protected class SingleRepositorySourceConnectionFactory implements RepositoryConnectionFactory {
-        private final RepositorySource source;
-
-        protected SingleRepositorySourceConnectionFactory( RepositorySource source ) {
-            CheckArg.isNotNull(source, "source");
-            this.source = source;
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see org.jboss.dna.graph.connectors.RepositoryConnectionFactory#createConnection(java.lang.String)
-         */
-        public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
-            if (source.getName().equals(sourceName)) {
-                return source.getConnection();
-            }
-            return null;
-        }
-    }
-
-    protected class ImporterCommands extends BasicGraphCommand implements SequencerOutput, CompositeCommand {
-        private final List<GraphCommand> commands = new ArrayList<GraphCommand>();
-        private final Map<Path, BasicCreateNodeCommand> createNodeCommands = new HashMap<Path, BasicCreateNodeCommand>();
-        private final NodeConflictBehavior conflictBehavior;
+    protected class ImporterOutput implements SequencerOutput {
+        private final Graph.Batch batch;
+        private Path latestPath;
+        private final LinkedList<Property> latestProperties = new LinkedList<Property>();
         private final Path destinationPath;
         private final NameFactory nameFactory;
         private final Name primaryTypeName;
 
-        protected ImporterCommands( Path destinationPath,
-                                    NodeConflictBehavior conflictBehavior ) {
+        protected ImporterOutput( Graph.Batch batch,
+                                  Path destinationPath ) {
+            CheckArg.isNotNull(batch, "batch");
             CheckArg.isNotNull(destinationPath, "destinationPath");
-            CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
-            this.conflictBehavior = conflictBehavior;
+            this.batch = batch;
             this.destinationPath = destinationPath;
             this.nameFactory = getContext().getValueFactories().getNameFactory();
             this.primaryTypeName = this.nameFactory.create("jcr:primaryType");
@@ -439,28 +258,11 @@
             if (nodePath.isAbsolute()) nodePath.relativeTo(pathFactory.createRootPath());
             nodePath = pathFactory.create(destinationPath, nodePath).getNormalizedPath();
             Property property = getContext().getPropertyFactory().create(propertyName, values);
-            BasicCreateNodeCommand command = createNodeCommands.get(nodePath);
-            if (command != null) {
-                // We've already created the node, so find that command and add to it.
-                Collection<Property> properties = command.getProperties();
-                // See if the property was already added and remove it if so
-                Iterator<Property> iter = properties.iterator();
-                while (iter.hasNext()) {
-                    Property existingProperty = iter.next();
-                    if (existingProperty.getName().equals(propertyName)) {
-                        iter.remove();
-                        break;
-                    }
-                }
-                command.getProperties().add(property);
-            } else {
-                // We haven't created the node yet (and we're assuming that we need to), so create the node
-                List<Property> properties = new ArrayList<Property>();
-                properties.add(property);
-                command = new BasicCreateNodeCommand(nodePath, properties, conflictBehavior);
-                createNodeCommands.put(nodePath, command);
-                commands.add(command);
-            }
+
+            // Set the latest information ...
+            if (!nodePath.equals(latestPath)) process();
+            latestPath = nodePath;
+            latestProperties.add(property);
         }
 
         /**
@@ -484,15 +286,22 @@
             setProperty(path, name, values);
         }
 
-        /**
-         * {@inheritDoc}
-         * 
-         * @see java.lang.Iterable#iterator()
-         */
-        public Iterator<GraphCommand> iterator() {
-            return this.commands.iterator();
+        protected void process() {
+            if (latestPath != null) {
+                if (latestProperties.isEmpty()) {
+                    batch.create(latestPath).and();
+                } else {
+                    Property firstProp = latestProperties.removeFirst();
+                    if (latestProperties.size() != 0) {
+                        Property[] props = latestProperties.toArray(new Property[latestProperties.size()]);
+                        batch.create(latestPath, firstProp, props).and();
+                    } else {
+                        batch.create(latestPath, firstProp).and();
+                    }
+                    latestProperties.clear();
+                }
+            }
         }
-
     }
 
     protected class ImporterContext implements SequencerContext {

Modified: trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
===================================================================
--- trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties	2008-10-23 18:46:32 UTC (rev 572)
@@ -47,12 +47,20 @@
 pathExpressionHasInvalidMatch = Invalid match expression "{0}" in the path expression "{1}"
 messageDigestNotFound = The "{0}" message digest algorithm could not be found
 
-executingGraphCommand = Executing {0}
-executedGraphCommand = Executed {0}
-closingCommandExecutor = Closing command executor
-closedCommandExecutor = Closed command executor
+executingRequest = Executing {0}
+executedRequest = Executed {0}
+closingRequestProcessor = Closing request processor
+closedRequestProcessor = Closed request processor
 multipleErrorsWhileExecutingRequests = {0} of the {1} requests resulted in errors
 unableToAddMoreRequestsToAlreadyExecutedBatch = Unable to add more requests to a batch of graph requests that has already been executed
+actualLocationIsNotSameAsInputLocation = The actual location of {0} is not the same as the current location of {1}
+actualLocationMustHavePath = The actual location of {0} must have a path
+actualNewLocationIsNotSameAsInputLocation = The actual new location of {0} is not the same as the input location of {1}
+actualNewLocationMustHavePath = The actual new location of {0} must have a path
+actualOldLocationIsNotSameAsInputLocation = The actual old location of {0} is not the same as the input location of {1}
+actualOldLocationMustHavePath = The actual old location of {0} must have a path
+actualNewLocationMustHaveSameParentAsOldLocation = The new location of {0} must be a sibling of the old location of {1}
+actualNewLocationMustHaveSameNameAsRequest = The new location of {0} must have the same name as in the request ({1})
 
 errorSequencingXmlDocument = An error was received while sequencing XML: {0}
 fatalErrorSequencingXmlDocument = A fatal error was received while sequencing XML: {0}

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -40,7 +40,6 @@
 import java.util.concurrent.TimeUnit;
 import javax.transaction.xa.XAResource;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GraphCommand;
 import org.jboss.dna.graph.connectors.BasicExecutionContext;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
@@ -61,8 +60,8 @@
 import org.jboss.dna.graph.requests.ReadNodeRequest;
 import org.jboss.dna.graph.requests.ReadPropertyRequest;
 import org.jboss.dna.graph.requests.Request;
-import org.jboss.dna.graph.requests.RequestProcessor;
 import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
+import org.jboss.dna.graph.requests.processor.RequestProcessor;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentMatcher;
@@ -771,22 +770,26 @@
 
         @Override
         public void process( CopyBranchRequest request ) {
-            // Do nothing
+            // Just update the actual location
+            request.setActualLocations(actualLocationOf(request.from()), actualLocationOf(request.into()));
         }
 
         @Override
         public void process( CreateNodeRequest request ) {
-            // Do nothing
+            // Just update the actual location
+            request.setActualLocationOfNode(actualLocationOf(request.at()));
         }
 
         @Override
         public void process( DeleteBranchRequest request ) {
-            // Do nothing
+            // Just update the actual location
+            request.setActualLocationOfNode(actualLocationOf(request.at()));
         }
 
         @Override
         public void process( MoveBranchRequest request ) {
-            // Do nothing
+            // Just update the actual location
+            request.setActualLocations(actualLocationOf(request.from()), actualLocationOf(request.into()));
         }
 
         @Override
@@ -797,6 +800,8 @@
                     request.addChild(child);
                 }
             }
+            // Set the actual location
+            request.setActualLocationOfNode(actualLocationOf(request.of()));
         }
 
         @Override
@@ -807,12 +812,23 @@
                     request.addProperty(property);
                 }
             }
+            // Set the actual location
+            request.setActualLocationOfNode(actualLocationOf(request.at()));
         }
 
         @Override
         public void process( UpdatePropertiesRequest request ) {
-            // Do nothing
+            // Just update the actual location
+            request.setActualLocationOfNode(actualLocationOf(request.on()));
         }
+
+        private Location actualLocationOf( Location location ) {
+            // If the location has a path, then use the location
+            if (location.hasPath()) return location;
+            // Otherwise, create a new location with an artificial path ...
+            Path path = context.getValueFactories().getPathFactory().create("/a/b/c/d");
+            return new Location(path, location.getIdProperties());
+        }
     }
 
     /**
@@ -828,10 +844,6 @@
         public void close() {
         }
 
-        public void execute( ExecutionContext context,
-                             GraphCommand... commands ) throws RepositorySourceException {
-        }
-
         @SuppressWarnings( "synthetic-access" )
         public void execute( ExecutionContext context,
                              Request request ) throws RepositorySourceException {

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/RepositorySourceLoadHarness.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/RepositorySourceLoadHarness.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/RepositorySourceLoadHarness.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -34,9 +34,9 @@
 import org.jboss.dna.common.i18n.MockI18n;
 import org.jboss.dna.common.util.Logger;
 import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.connectors.RepositoryConnection;
-import org.jboss.dna.graph.connectors.RepositoryConnectionPool;
-import org.jboss.dna.graph.connectors.RepositorySourceException;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.properties.basic.BasicPath;
+import org.jboss.dna.graph.requests.ReadNodeRequest;
 
 /**
  * A test harness for using repository connections under load.
@@ -168,8 +168,8 @@
 
     /**
      * Return an operation factory that produces {@link RepositoryOperation} instances that each call
-     * {@link RepositoryConnection#execute(ExecutionContext, org.jboss.dna.graph.commands.GraphCommand...)} the supplied number of
-     * times, intermixed with random math operations and {@link Thread#yield() yielding}.
+     * {@link RepositoryConnection#execute(ExecutionContext, org.jboss.dna.graph.requests.Request)} the supplied number of times,
+     * intermixed with random math operations and {@link Thread#yield() yielding}.
      * 
      * @param callsPerOperation the number of <code>load</code> calls per RepositoryOperation
      * @return the factory
@@ -215,7 +215,7 @@
                 if (i % 2 == 0) {
                     Thread.yield();
                 }
-                connection.execute(context);
+                connection.execute(context, new ReadNodeRequest(new Location(BasicPath.ROOT)));
                 int int2 = random(this.hashCode() ^ (int)System.nanoTime() + i);
                 total += Math.min(Math.abs(Math.max(int1, int2) + int1 * int2 / 3), count);
             }

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/SimpleRepository.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/SimpleRepository.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/SimpleRepository.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -73,7 +73,6 @@
 
     private ConcurrentMap<Path, Map<Name, Property>> data = new ConcurrentHashMap<Path, Map<Name, Property>>();
     private final String repositoryName;
-    private Name uuidPropertyName = DEFAULT_UUID_PROPERTY_NAME;
     private boolean shutdown = false;
 
     public SimpleRepository( String repositoryName ) {
@@ -93,21 +92,6 @@
     }
 
     /**
-     * @return uuidPropertyName
-     */
-    public Name getUuidPropertyName() {
-        return uuidPropertyName;
-    }
-
-    /**
-     * @param uuidPropertyName Sets uuidPropertyName to the specified value.
-     */
-    public void setUuidPropertyName( Name uuidPropertyName ) {
-        if (uuidPropertyName == null) uuidPropertyName = DEFAULT_UUID_PROPERTY_NAME;
-        this.uuidPropertyName = uuidPropertyName;
-    }
-
-    /**
      * Get the current modifiable map of property data
      * 
      * @return data
@@ -159,9 +143,14 @@
             create(context, pathObj.getParent().getString(context.getNamespaceRegistry()));
         }
         Property property = propertyFactory.create(propertyName, values);
-        Map<Name, Property> properties = new HashMap<Name, Property>();
-        Map<Name, Property> existingProperties = data.putIfAbsent(pathObj, properties);
-        if (existingProperties == null) existingProperties = properties;
+        Map<Name, Property> newProperties = new HashMap<Name, Property>();
+        Map<Name, Property> existingProperties = data.putIfAbsent(pathObj, newProperties);
+        if (existingProperties == null) {
+            existingProperties = newProperties;
+            UUID uuid = context.getValueFactories().getUuidFactory().create();
+            Property uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, uuid);
+            newProperties.put(DnaLexicon.UUID, uuidProperty);
+        }
         existingProperties.put(property.getName(), property);
         return this;
     }
@@ -180,13 +169,19 @@
         Path pathObj = pathFactory.create(path);
         Path ancestorPath = pathObj;
         while (!ancestorPath.isRoot()) {
-            data.putIfAbsent(ancestorPath, new HashMap<Name, Property>());
+            // Add a UUID property ...
+            if (!data.containsKey(ancestorPath)) {
+                Map<Name, Property> props = new HashMap<Name, Property>();
+                UUID uuid = context.getValueFactories().getUuidFactory().create();
+                Property uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, uuid);
+                props.put(DnaLexicon.UUID, uuidProperty);
+                data.putIfAbsent(ancestorPath, props);
+            }
             ancestorPath = ancestorPath.getParent();
         }
-        Name uuidName = context.getValueFactories().getNameFactory().create(this.getUuidPropertyName());
         UUID uuid = context.getValueFactories().getUuidFactory().create();
-        Property uuidProperty = context.getPropertyFactory().create(uuidName, uuid);
-        data.get(pathObj).put(uuidProperty.getName(), uuidProperty);
+        Property uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, uuid);
+        data.get(pathObj).put(DnaLexicon.UUID, uuidProperty);
         return this;
     }
 

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/SimpleRepositorySource.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/SimpleRepositorySource.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/SimpleRepositorySource.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -25,29 +25,29 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import javax.naming.Reference;
 import javax.transaction.xa.XAResource;
 import net.jcip.annotations.ThreadSafe;
+import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.ActsOnPath;
-import org.jboss.dna.graph.commands.CreateNodeCommand;
-import org.jboss.dna.graph.commands.DeleteBranchCommand;
-import org.jboss.dna.graph.commands.GetChildrenCommand;
-import org.jboss.dna.graph.commands.GetPropertiesCommand;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.commands.SetPropertiesCommand;
-import org.jboss.dna.graph.commands.executor.AbstractCommandExecutor;
-import org.jboss.dna.graph.commands.executor.CommandExecutor;
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
+import org.jboss.dna.graph.properties.PathFactory;
 import org.jboss.dna.graph.properties.PathNotFoundException;
 import org.jboss.dna.graph.properties.Property;
-import org.jboss.dna.graph.properties.basic.BasicSingleValueProperty;
+import org.jboss.dna.graph.requests.CopyBranchRequest;
+import org.jboss.dna.graph.requests.CreateNodeRequest;
+import org.jboss.dna.graph.requests.DeleteBranchRequest;
+import org.jboss.dna.graph.requests.MoveBranchRequest;
+import org.jboss.dna.graph.requests.ReadAllChildrenRequest;
+import org.jboss.dna.graph.requests.ReadAllPropertiesRequest;
 import org.jboss.dna.graph.requests.Request;
+import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
+import org.jboss.dna.graph.requests.processor.RequestProcessor;
 
 /**
  * A {@link RepositorySource} for a {@link SimpleRepository simple repository}.
@@ -246,32 +246,126 @@
          * {@inheritDoc}
          * 
          * @see org.jboss.dna.graph.connectors.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
-         *      org.jboss.dna.graph.commands.GraphCommand[])
-         */
-        public void execute( ExecutionContext context,
-                             GraphCommand... commands ) throws RepositorySourceException {
-            assert context != null;
-            if (repository.isShutdown()) {
-                throw new RepositorySourceException(getName(), "The repository \"" + repository.getRepositoryName()
-                                                               + "\" is no longer available");
-            }
-            // Now execute the commands ...
-            CommandExecutor executor = new Executor(this.repository, context, this.getSourceName());
-            for (GraphCommand command : commands) {
-                executor.execute(command);
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see org.jboss.dna.graph.connectors.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
          *      org.jboss.dna.graph.requests.Request)
          */
         public void execute( ExecutionContext context,
                              Request request ) throws RepositorySourceException {
-            // TODO
-            throw new UnsupportedOperationException();
+            final PathFactory pathFactory = context.getValueFactories().getPathFactory();
+            final SimpleRepository repository = this.repository;
+            RequestProcessor processor = new RequestProcessor(getSourceName(), context) {
+                @Override
+                public void process( ReadAllChildrenRequest request ) {
+                    Map<Name, Property> properties = getProperties(request, request.of());
+                    Path targetPath = request.of().getPath();
+                    if (properties == null) return;
+                    Property uuidProperty = properties.get(DnaLexicon.UUID);
+                    // Iterate through all of the properties, looking for any paths that are children of the path ...
+                    Map<Path, Map<Name, Property>> data = repository.getData();
+                    List<Path.Segment> childSegments = new LinkedList<Path.Segment>();
+                    for (Path path : data.keySet()) {
+                        if (!path.isRoot() && path.getParent().equals(targetPath)) {
+                            childSegments.add(path.getLastSegment());
+                        }
+                    }
+                    // This does not store children order, so sort ...
+                    Collections.sort(childSegments);
+                    // Now get the children ...
+                    for (Path.Segment childSegment : childSegments) {
+                        Path childPath = pathFactory.create(targetPath, childSegment);
+                        Map<Name, Property> childProperties = repository.getData().get(childPath);
+                        Property childUuidProperty = childProperties.get(DnaLexicon.UUID);
+                        request.addChild(childPath, childUuidProperty);
+                    }
+                    request.setActualLocationOfNode(request.of().with(uuidProperty));
+                }
+
+                @Override
+                public void process( ReadAllPropertiesRequest request ) {
+                    Map<Name, Property> properties = getProperties(request, request.at());
+                    if (properties == null) return;
+                    Property uuidProperty = properties.get(DnaLexicon.UUID);
+                    for (Property property : properties.values()) {
+                        if (property != uuidProperty) request.addProperty(property);
+                    }
+                    request.setActualLocationOfNode(request.at().with(uuidProperty));
+                }
+
+                @Override
+                public void process( CopyBranchRequest request ) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public void process( CreateNodeRequest request ) {
+                    Path targetPath = request.at().getPath();
+                    ExecutionContext context = getExecutionContext();
+                    repository.create(context, targetPath.getString(context.getNamespaceRegistry()));
+                    Map<Name, Property> properties = repository.getData().get(targetPath);
+                    assert properties != null;
+                    // Set the UUID if the request has one ...
+                    Property uuidProperty = request.at().getIdProperty(DnaLexicon.UUID);
+                    if (uuidProperty != null) {
+                        properties.put(uuidProperty.getName(), uuidProperty);
+                        request.setActualLocationOfNode(request.at());
+                    } else {
+                        uuidProperty = properties.get(DnaLexicon.UUID);
+                        request.setActualLocationOfNode(request.at().with(uuidProperty));
+                    }
+                    for (Property property : request.properties()) {
+                        if (property != null) properties.put(property.getName(), property);
+                    }
+                }
+
+                @Override
+                public void process( DeleteBranchRequest request ) {
+                    // Iterate through all of the dataq, looking for any paths that are children of the path ...
+                    Path targetPath = request.at().getPath();
+                    Map<Path, Map<Name, Property>> data = repository.getData();
+                    Map<Name, Property> properties = repository.getData().get(targetPath);
+                    Property uuidProperty = properties.get(DnaLexicon.UUID);
+                    for (Path path : data.keySet()) {
+                        if (!path.isRoot() && path.isAtOrBelow(targetPath)) {
+                            data.remove(path);
+                        }
+                    }
+                    request.setActualLocationOfNode(request.at().with(uuidProperty));
+                }
+
+                @Override
+                public void process( MoveBranchRequest request ) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public void process( UpdatePropertiesRequest request ) {
+                    Map<Name, Property> properties = getProperties(request, request.on());
+                    if (properties == null) return;
+                    Property uuidProperty = properties.get(DnaLexicon.UUID);
+                    for (Property property : request.properties()) {
+                        if (property != uuidProperty) properties.put(property.getName(), property);
+                    }
+                    request.setActualLocationOfNode(request.on().with(uuidProperty));
+                }
+
+                protected Map<Name, Property> getProperties( Request request,
+                                                             Location location ) {
+                    Path targetPath = location.getPath();
+                    if (targetPath == null) throw new UnsupportedOperationException();
+                    Map<Name, Property> properties = repository.getData().get(targetPath);
+                    if (properties == null) {
+                        Path ancestor = targetPath.getParent();
+                        while (ancestor != null) {
+                            if (repository.getData().get(targetPath) != null) break;
+                            ancestor = ancestor.getParent();
+                        }
+                        if (ancestor == null) ancestor = getExecutionContext().getValueFactories().getPathFactory().createRootPath();
+                        request.setError(new PathNotFoundException(location, ancestor));
+                        return null;
+                    }
+                    return properties;
+                }
+            };
+            processor.process(request);
         }
 
         /**
@@ -326,132 +420,5 @@
         public RepositorySourceListener getListener() {
             return listener;
         }
-
     }
-
-    protected class Executor extends AbstractCommandExecutor {
-        private final SimpleRepository repository;
-        private final Name uuidPropertyName;
-
-        protected Executor( SimpleRepository repository,
-                            ExecutionContext context,
-                            String sourceName ) {
-            super(context, sourceName);
-            this.repository = repository;
-            this.uuidPropertyName = context.getValueFactories().getNameFactory().create(this.repository.getUuidPropertyName());
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.GetChildrenCommand)
-         */
-        @Override
-        public void execute( GetChildrenCommand command ) throws RepositorySourceException {
-            Path targetPath = command.getPath();
-            Map<Name, Property> properties = getProperties(command);
-            if (properties == null) return;
-            // Iterate through all of the properties, looking for any paths that are children of the path ...
-            Map<Path, Map<Name, Property>> data = repository.getData();
-            List<Path.Segment> childSegments = new LinkedList<Path.Segment>();
-            for (Path path : data.keySet()) {
-                if (!path.isRoot() && path.getParent().equals(targetPath)) {
-                    childSegments.add(path.getLastSegment());
-                }
-            }
-            // This does not store children order, so sort ...
-            Collections.sort(childSegments);
-            for (Path.Segment childSegment : childSegments) {
-                Map<Name, Property> childProperties = repository.getData().get(targetPath);
-                Property uuidProperty = childProperties.get(uuidPropertyName);
-                command.addChild(childSegment,
-                                 uuidProperty == null ? new BasicSingleValueProperty(uuidPropertyName, UUID.randomUUID()) : uuidProperty);
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.GetPropertiesCommand)
-         */
-        @Override
-        public void execute( GetPropertiesCommand command ) throws RepositorySourceException {
-            Map<Name, Property> properties = getProperties(command);
-            if (properties == null) return;
-            for (Property property : properties.values()) {
-                if (!property.getName().equals(this.uuidPropertyName)) {
-                    command.setProperty(property);
-                }
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.CreateNodeCommand)
-         */
-        @Override
-        public void execute( CreateNodeCommand command ) throws RepositorySourceException {
-            Path targetPath = command.getPath();
-            ExecutionContext context = getExecutionContext();
-            repository.create(context, targetPath.getString(context.getNamespaceRegistry()));
-            Map<Name, Property> properties = repository.getData().get(targetPath);
-            assert properties != null;
-            for (Property property : command.getProperties()) {
-                if (!property.getName().equals(this.uuidPropertyName)) {
-                    properties.put(property.getName(), property);
-                }
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.SetPropertiesCommand)
-         */
-        @Override
-        public void execute( SetPropertiesCommand command ) throws RepositorySourceException {
-            Map<Name, Property> properties = getProperties(command);
-            if (properties == null) return;
-            for (Property property : command.getProperties()) {
-                if (!property.getName().equals(this.uuidPropertyName)) {
-                    properties.put(property.getName(), property);
-                }
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.DeleteBranchCommand)
-         */
-        @Override
-        public void execute( DeleteBranchCommand command ) throws RepositorySourceException {
-            // Iterate through all of the dataq, looking for any paths that are children of the path ...
-            Path targetPath = command.getPath();
-            Map<Path, Map<Name, Property>> data = repository.getData();
-            for (Path path : data.keySet()) {
-                if (!path.isRoot() && path.isAtOrBelow(targetPath)) {
-                    data.remove(path);
-                }
-            }
-        }
-
-        protected <T extends ActsOnPath & GraphCommand> Map<Name, Property> getProperties( T command ) {
-            Path targetPath = command.getPath();
-            Map<Name, Property> properties = repository.getData().get(targetPath);
-            if (properties == null) {
-                Path ancestor = targetPath.getParent();
-                while (ancestor != null) {
-                    if (repository.getData().get(targetPath) != null) break;
-                    ancestor = ancestor.getParent();
-                }
-                if (ancestor == null) ancestor = getExecutionContext().getValueFactories().getPathFactory().createRootPath();
-                command.setError(new PathNotFoundException(targetPath, ancestor));
-                return null;
-            }
-            return properties;
-        }
-    }
-
 }

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/TimeDelayingRepositorySource.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/TimeDelayingRepositorySource.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connectors/TimeDelayingRepositorySource.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -34,7 +34,6 @@
 import net.jcip.annotations.ThreadSafe;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GraphCommand;
 import org.jboss.dna.graph.requests.Request;
 
 /**
@@ -312,9 +311,12 @@
 
         /**
          * {@inheritDoc}
+         * 
+         * @see org.jboss.dna.graph.connectors.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
+         *      org.jboss.dna.graph.requests.Request)
          */
         public void execute( ExecutionContext context,
-                             GraphCommand... commands ) {
+                             Request request ) throws RepositorySourceException {
             long delay = this.loadDelay.get();
             if (delay > 0l) {
                 try {
@@ -327,18 +329,6 @@
             this.loadCount.incrementAndGet();
         }
 
-        /**
-         * {@inheritDoc}
-         * 
-         * @see org.jboss.dna.graph.connectors.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
-         *      org.jboss.dna.graph.requests.Request)
-         */
-        public void execute( ExecutionContext context,
-                             Request request ) throws RepositorySourceException {
-            // TODO
-            throw new UnsupportedOperationException();
-        }
-
         public void setLoadResponse( boolean response ) {
             this.loadResponse.set(response);
         }

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/properties/basic/BasicPathTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -21,11 +21,11 @@
  */
 package org.jboss.dna.graph.properties.basic;
 
-import static org.jboss.dna.graph.properties.basic.IsPathContaining.hasSegments;
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsNot.not;
 import static org.hamcrest.core.IsNull.nullValue;
 import static org.hamcrest.core.IsSame.sameInstance;
+import static org.jboss.dna.graph.properties.basic.IsPathContaining.hasSegments;
 import static org.junit.Assert.assertThat;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -37,13 +37,6 @@
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.ValueFormatException;
-import org.jboss.dna.graph.properties.basic.BasicName;
-import org.jboss.dna.graph.properties.basic.BasicNamespaceRegistry;
-import org.jboss.dna.graph.properties.basic.BasicPath;
-import org.jboss.dna.graph.properties.basic.BasicPathSegment;
-import org.jboss.dna.graph.properties.basic.NameValueFactory;
-import org.jboss.dna.graph.properties.basic.PathValueFactory;
-import org.jboss.dna.graph.properties.basic.StringValueFactory;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -411,6 +404,41 @@
     }
 
     @Test
+    public void shouldConsiderTwoRootNodesToHaveSameAncestor() {
+        assertThat(ROOT.hasSameAncestor(ROOT), is(true));
+    }
+
+    @Test
+    public void shouldConsiderTwoNotRootSiblingNodesToHaveSameAncestor() {
+        Path path1 = pathFactory.create("/a/y/z");
+        Path path2 = pathFactory.create("/a/y/c");
+        assertThat(path1.hasSameAncestor(path2), is(true));
+
+        path1 = pathFactory.create("/a/z");
+        path2 = pathFactory.create("/a/c");
+        assertThat(path1.hasSameAncestor(path2), is(true));
+
+        path1 = pathFactory.create("/z");
+        path2 = pathFactory.create("/c");
+        assertThat(path1.hasSameAncestor(path2), is(true));
+    }
+
+    @Test
+    public void shouldNotConsiderTwoNonSiblingNodesToHaveSameAncestor() {
+        Path path1 = pathFactory.create("/a/y/z");
+        Path path2 = pathFactory.create("/a/x/c");
+        assertThat(path1.hasSameAncestor(path2), is(false));
+
+        path1 = pathFactory.create("/a/z");
+        path2 = pathFactory.create("/b/c");
+        assertThat(path1.hasSameAncestor(path2), is(false));
+
+        path1 = pathFactory.create("/z");
+        path2 = pathFactory.create("/a/c");
+        assertThat(path1.hasSameAncestor(path2), is(false));
+    }
+
+    @Test
     public void shouldNeverBeDecendantOfNullPath() {
         assertThat(path.isDecendantOf(null), is(false));
         assertThat(ROOT.isDecendantOf(null), is(false));

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/util/GraphImporterTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/util/GraphImporterTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/util/GraphImporterTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -37,10 +37,9 @@
 import org.jboss.dna.common.util.StringUtil;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.CompositeCommand;
-import org.jboss.dna.graph.commands.CreateNodeCommand;
-import org.jboss.dna.graph.commands.GraphCommand;
 import org.jboss.dna.graph.connectors.BasicExecutionContext;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
@@ -49,6 +48,8 @@
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
+import org.jboss.dna.graph.requests.CompositeRequest;
+import org.jboss.dna.graph.requests.CreateNodeRequest;
 import org.jboss.dna.graph.requests.Request;
 import org.jboss.dna.graph.xml.DnaDtdLexicon;
 import org.jboss.dna.graph.xml.DnaXmlLexicon;
@@ -62,12 +63,12 @@
  */
 public class GraphImporterTest {
 
+    private Graph graph;
     private GraphImporter importer;
     private String sourceName;
     private ExecutionContext context;
     private URI xmlContent;
     private MockRepositoryConnection connection;
-    private GraphCommand lastExecutedCommand;
     private Request lastExecutedRequest;
     private Path destinationPath;
     @Mock
@@ -85,7 +86,8 @@
         context.getNamespaceRegistry().register("nt", "http://www.jcp.org/jcr/nt/1.0");
         sourceName = "sourceA";
         destinationPath = context.getValueFactories().getPathFactory().create("/a/b");
-        importer = new GraphImporter(sources, context);
+        graph = Graph.create(sourceName, sources, context);
+        importer = new GraphImporter(graph);
         connection = new MockRepositoryConnection();
         stub(sources.createConnection(sourceName)).toReturn(connection);
     }
@@ -93,10 +95,11 @@
     @Test
     public void shouldImportXmlContentAndGenerateTheCorrectCommands() throws Exception {
         System.out.println(xmlContent);
-        importer.importXml(xmlContent).into(sourceName, destinationPath); // writes commands as CompositeCommand to
+        Graph.Batch batch = importer.importXml(xmlContent, new Location(destinationPath));
+        batch.execute();
         // 'lastExecutedCommand'
-        assertThat(lastExecutedCommand, is(instanceOf(CompositeCommand.class)));
-        Iterator<GraphCommand> iter = ((CompositeCommand)lastExecutedCommand).iterator();
+        assertThat(lastExecutedRequest, is(instanceOf(CompositeRequest.class)));
+        Iterator<Request> iter = ((CompositeRequest)lastExecutedRequest).iterator();
         // assertCreateNode(iter, "/a/b/", "jcr:primaryType={http://www.jboss.org/dna/xml/1.0}document");
         assertCreateNode(iter, "/a/b/dnaxml:comment[1]", "any properties"); // jcr:primaryType and dnaxml:commentContent
         assertCreateNode(iter, "/a/b/dna:system[1]", "jcr:primaryType={http://www.jcp.org/jcr/nt/1.0}unstructured");
@@ -116,16 +119,16 @@
         assertThat(iter.hasNext(), is(false));
     }
 
-    public void assertCreateNode( Iterator<GraphCommand> iterator,
+    public void assertCreateNode( Iterator<Request> iterator,
                                   String path,
                                   String... properties ) {
-        GraphCommand nextCommand = iterator.next();
-        assertThat(nextCommand, is(instanceOf(CreateNodeCommand.class)));
-        CreateNodeCommand createNode = (CreateNodeCommand)nextCommand;
+        Request nextCommand = iterator.next();
+        assertThat(nextCommand, is(instanceOf(CreateNodeRequest.class)));
+        CreateNodeRequest createNode = (CreateNodeRequest)nextCommand;
         Path expectedPath = context.getValueFactories().getPathFactory().create(path);
-        assertThat(createNode.getPath(), is(expectedPath));
+        assertThat(createNode.at().getPath(), is(expectedPath));
         Map<Name, Property> propertiesByName = new HashMap<Name, Property>();
-        for (Property prop : createNode.getProperties()) {
+        for (Property prop : createNode.properties()) {
             propertiesByName.put(prop.getName(), prop);
         }
         for (String propertyStr : properties) {
@@ -156,12 +159,6 @@
 
         @SuppressWarnings( "synthetic-access" )
         public void execute( ExecutionContext context,
-                             GraphCommand... commands ) throws RepositorySourceException {
-            lastExecutedCommand = commands[0];
-        }
-
-        @SuppressWarnings( "synthetic-access" )
-        public void execute( ExecutionContext context,
                              Request request ) throws RepositorySourceException {
             lastExecutedRequest = request;
         }

Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java	                        (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrLexicon.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -0,0 +1,38 @@
+/*
+ * 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.jcr;
+
+import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.properties.basic.BasicName;
+
+/**
+ * @author Randall Hauch
+ */
+class JcrLexicon {
+
+    public static class Namespace {
+        public static final String URI = "http://www.jcp.org/jcr/1.0";
+        public static final String PREFIX = "jcr";
+    }
+
+    public static final Name UUID = new BasicName(Namespace.URI, "uuid");
+}


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

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -39,6 +39,7 @@
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.ExecutionContextFactory;
+import org.jboss.dna.graph.Graph;
 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
 import com.google.common.base.ReferenceType;
 import com.google.common.collect.ReferenceMap;
@@ -258,7 +259,7 @@
         // Ensure valid workspace name
         if (workspaceName == null) workspaceName = JcrI18n.defaultWorkspaceName.text();
         // Create session
-        return new JcrSession(this, execContext, workspaceName, connectionFactory.createConnection(workspaceName),
-                              new ReferenceMap<UUID, Node>(ReferenceType.STRONG, ReferenceType.SOFT));
+        Graph graph = Graph.create(workspaceName, connectionFactory, execContext);
+        return new JcrSession(this, workspaceName, graph, new ReferenceMap<UUID, Node>(ReferenceType.STRONG, ReferenceType.SOFT));
     }
 }

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -49,14 +49,11 @@
 import org.jboss.dna.common.util.StringUtil;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.commands.basic.BasicGetNodeCommand;
-import org.jboss.dna.graph.connectors.RepositoryConnection;
+import org.jboss.dna.graph.Graph;
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.UuidFactory;
 import org.jboss.dna.graph.properties.ValueFactories;
-import org.jboss.dna.graph.properties.Path.Segment;
 import org.xml.sax.ContentHandler;
 import com.google.common.base.ReferenceType;
 import com.google.common.collect.ReferenceMap;
@@ -69,8 +66,8 @@
 class JcrSession implements Session {
 
     private final Repository repository;
+    private final Graph graph;
     private final ExecutionContext executionContext;
-    private RepositoryConnection connection;
     private final ReferenceMap<UUID, Node> nodesByUuid;
     private final ReferenceMap<String, Node> nodesByJcrUuid;
     private boolean isLive;
@@ -78,18 +75,17 @@
     private JcrRootNode rootNode;
 
     JcrSession( Repository repository,
-                ExecutionContext executionContext,
                 String workspaceName,
-                RepositoryConnection connection,
+                Graph graph,
                 ReferenceMap<UUID, Node> nodesByUuid ) throws RepositoryException {
         assert repository != null;
-        assert executionContext != null;
+        assert graph != null;
         assert workspaceName != null;
-        assert connection != null;
         assert nodesByUuid != null;
         this.repository = repository;
-        this.executionContext = executionContext;
-        this.connection = connection;
+        this.graph = graph;
+        this.executionContext = graph.getContext();
+        assert this.executionContext != null;
         this.nodesByUuid = nodesByUuid;
         this.nodesByJcrUuid = new ReferenceMap<String, Node>(ReferenceType.STRONG, ReferenceType.SOFT);
         this.isLive = true;
@@ -97,6 +93,10 @@
         this.workspace = new JcrWorkspace(this, workspaceName);
     }
 
+    ExecutionContext getExecutionContext() {
+        return this.executionContext;
+    }
+
     /**
      * {@inheritDoc}
      * 
@@ -122,16 +122,6 @@
         }
     }
 
-    private void execute( GraphCommand... commands ) throws RepositoryException {
-        try {
-            connection.execute(executionContext, commands);
-        } catch (RuntimeException error) {
-            throw error;
-        } catch (Exception error) {
-            throw new RepositoryException(error);
-        }
-    }
-
     /**
      * {@inheritDoc}
      * 
@@ -204,10 +194,6 @@
         return StringUtil.EMPTY_STRING_ARRAY;
     }
 
-    ExecutionContext getExecutionContext() {
-        return executionContext;
-    }
-
     /**
      * {@inheritDoc}
      * 
@@ -232,25 +218,29 @@
         if (path.isRoot()) {
             return getRootNode();
         }
-        // Since we don't know whether path refers to a node or property, get the parent contents, which must refer to a node
-        Path parentPath = path.getParent();
-        BasicGetNodeCommand getNodeCommand = new BasicGetNodeCommand(parentPath);
-        execute(getNodeCommand);
-        // First search for a child with the last name in the path
-        Segment lastSeg = path.getLastSegment();
-        Name name = lastSeg.getName();
-        for (Segment seg : getNodeCommand.getChildren()) {
-            if (seg.getName().equals(name)) {
+        // Since we don't know whether path refers to a node or a property, look to see if we can tell it's a node ...
+        if (path.getLastSegment().hasIndex()) {
+            try {
                 return getNode(path);
+            } catch (org.jboss.dna.graph.properties.PathNotFoundException e) {
+                // If the node isn't found, throw a PathNotFoundException
+                throw new PathNotFoundException(JcrI18n.pathNotFound.text(path));
             }
         }
-        // If a node isn't found & last segment contains no index, get parent node & search for a property with the last name in
-        // the path
-        if (!lastSeg.hasIndex()) {
-            return getNode(parentPath).getProperty(lastSeg.getString(executionContext.getNamespaceRegistry()));
+        // We can't tell from the name, so try a node first ...
+        try {
+            return getNode(path);
+        } catch (org.jboss.dna.graph.properties.PathNotFoundException e) {
+            // A node was not found, so treat look for a node using the parent as the node's path ...
+            Path parentPath = path.getParent();
+            Name propertyName = path.getLastSegment().getName();
+            try {
+                return getNode(parentPath).getProperty(propertyName.getString(executionContext.getNamespaceRegistry()));
+            } catch (org.jboss.dna.graph.properties.PathNotFoundException e2) {
+                // If the node isn't found, throw a PathNotFoundException
+                throw new PathNotFoundException(JcrI18n.pathNotFound.text(path));
+            }
         }
-        // If a property isn't found, throw a PathNotFoundException
-        throw new PathNotFoundException(JcrI18n.pathNotFound.text(path));
     }
 
     /**
@@ -292,11 +282,10 @@
 
     private Node getNode( Path path ) throws RepositoryException {
         // Get node from source
-        BasicGetNodeCommand command = new BasicGetNodeCommand(path);
-        execute(command);
+        org.jboss.dna.graph.Node graphNode = graph.getNodeAt(path);
         // First check if node already exists. We don't need to check for changes since that will be handled by an observer
-        org.jboss.dna.graph.properties.Property dnaUuidProp = command.getPropertiesByName().get(executionContext.getValueFactories().getNameFactory().create("jcr:uuid"));
-        if (dnaUuidProp == null) dnaUuidProp = command.getPropertiesByName().get(DnaLexicon.UUID);
+        org.jboss.dna.graph.properties.Property dnaUuidProp = graphNode.getPropertiesByName().get(JcrLexicon.UUID);
+        if (dnaUuidProp == null) dnaUuidProp = graphNode.getPropertiesByName().get(DnaLexicon.UUID);
         if (dnaUuidProp != null) {
             UUID uuid = executionContext.getValueFactories().getUuidFactory().create(dnaUuidProp.getValues()).next();
             Node node = getNode(uuid);
@@ -309,7 +298,7 @@
         Path parentPath = path.getParent();
         if (parentPath.isRoot()) node = new JcrNode(this, ((JcrRootNode)getRootNode()).getInternalUuid(), path.getLastSegment());
         else node = new JcrNode(this, ((JcrNode)getNode(parentPath)).getInternalUuid(), path.getLastSegment());
-        populateNode(node, command);
+        populateNode(node, graphNode);
         return node;
     }
 
@@ -342,7 +331,7 @@
      * 
      * @see javax.jcr.Session#getRootNode()
      */
-    public Node getRootNode() throws RepositoryException {
+    public Node getRootNode() {
         // Return cached root node if available
         if (rootNode != null) {
             return rootNode;
@@ -352,10 +341,7 @@
         assert executionContext.getValueFactories().getPathFactory() != null;
         rootNode = new JcrRootNode(this);
         // Get root node from source
-        BasicGetNodeCommand getNodeCommand = new BasicGetNodeCommand(
-                                                                     executionContext.getValueFactories().getPathFactory().createRootPath());
-        execute(getNodeCommand);
-        populateNode(rootNode, getNodeCommand);
+        populateNode(rootNode, graph.getNodeAt(executionContext.getValueFactories().getPathFactory().createRootPath()));
         return rootNode;
     }
 
@@ -488,10 +474,6 @@
         if (!isLive()) {
             return;
         }
-        if (connection != null) {
-            connection.close();
-            connection = null;
-        }
         LoginContext loginContext = executionContext.getLoginContext();
         if (loginContext != null) {
             try {
@@ -516,12 +498,12 @@
     }
 
     private void populateNode( AbstractJcrNode node,
-                               BasicGetNodeCommand getNodeCommand ) {
+                               org.jboss.dna.graph.Node graphNode ) {
         // TODO: What do we do to validate node against its primary type?
         assert node != null;
-        assert getNodeCommand != null;
+        assert graphNode != null;
         // Create JCR children for corresponding DNA children
-        node.setChildren(getNodeCommand.getChildren());
+        node.setChildren(graphNode.getChildrenSegments());
         // Create JCR properties for corresponding DNA properties
         Set<Property> properties = new HashSet<Property>();
         UUID uuid = null;
@@ -530,7 +512,7 @@
         UuidFactory uuidFactory = executionContext.getValueFactories().getUuidFactory();
         org.jboss.dna.graph.properties.Property dnaUuidProp = null;
         boolean referenceable = false;
-        for (org.jboss.dna.graph.properties.Property dnaProp : getNodeCommand.getProperties()) {
+        for (org.jboss.dna.graph.properties.Property dnaProp : graphNode.getProperties()) {
             Name name = dnaProp.getName();
             if (dnaProp.isMultiple()) properties.add(new JcrMultiValueProperty(node, executionContext, name, dnaProp));
             else {

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -46,6 +46,7 @@
 import javax.security.auth.login.LoginContext;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.ExecutionContextFactory;
+import org.jboss.dna.graph.Graph;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
 import org.jboss.dna.graph.connectors.SimpleRepository;
@@ -107,27 +108,25 @@
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNoRepository() throws Exception {
-        new JcrSession(null, executionContext, WORKSPACE_NAME, connection, nodesByUuid);
+        Graph graph = Graph.create(WORKSPACE_NAME, connectionFactory, executionContext);
+        new JcrSession(null, WORKSPACE_NAME, graph, nodesByUuid);
     }
 
     @Test( expected = AssertionError.class )
-    public void shouldNotAllowNoExecutionContext() throws Exception {
-        new JcrSession(repository, null, WORKSPACE_NAME, connection, nodesByUuid);
-    }
-
-    @Test( expected = AssertionError.class )
     public void shouldNotAllowNoWorkspaceName() throws Exception {
-        new JcrSession(repository, executionContext, null, connection, nodesByUuid);
+        Graph graph = Graph.create(WORKSPACE_NAME, connectionFactory, executionContext);
+        new JcrSession(repository, null, graph, nodesByUuid);
     }
 
     @Test( expected = AssertionError.class )
-    public void shouldNotAllowNoConnection() throws Exception {
-        new JcrSession(repository, executionContext, WORKSPACE_NAME, null, nodesByUuid);
+    public void shouldNotAllowNoGraph() throws Exception {
+        new JcrSession(repository, WORKSPACE_NAME, null, nodesByUuid);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNoUuid2NodeMap() throws Exception {
-        new JcrSession(repository, executionContext, WORKSPACE_NAME, connection, null);
+        Graph graph = Graph.create(WORKSPACE_NAME, connectionFactory, executionContext);
+        new JcrSession(repository, WORKSPACE_NAME, graph, null);
     }
 
     @Test( expected = UnsupportedOperationException.class )
@@ -212,8 +211,9 @@
         ExecutionContext executionContext = Mockito.mock(ExecutionContext.class);
         stub(executionContext.getSubject()).toReturn(subject);
         stub(executionContext.getLoginContext()).toReturn(Mockito.mock(LoginContext.class));
-        Session session = new JcrSession(repository, executionContext, WORKSPACE_NAME, Mockito.mock(RepositoryConnection.class),
-                                         nodesByUuid);
+        Graph graph = Mockito.mock(Graph.class);
+        stub(graph.getContext()).toReturn(executionContext);
+        Session session = new JcrSession(repository, WORKSPACE_NAME, graph, nodesByUuid);
         try {
             assertThat(session.getUserID(), is("name"));
         } finally {
@@ -224,8 +224,8 @@
     @Test
     public void shouldProvideRootNode() throws Exception {
         ReferenceMap<UUID, Node> nodesByUuid = new ReferenceMap<UUID, Node>(ReferenceType.STRONG, ReferenceType.SOFT);
-        Session session = new JcrSession(repository, executionContext, WORKSPACE_NAME,
-                                         connectionFactory.createConnection(WORKSPACE_NAME), nodesByUuid);
+        Graph graph = Graph.create(WORKSPACE_NAME, connectionFactory, executionContext);
+        Session session = new JcrSession(repository, WORKSPACE_NAME, graph, nodesByUuid);
         assertThat(nodesByUuid.isEmpty(), is(true));
         Node root = session.getRootNode();
         assertThat(root, notNullValue());

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	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/dna-repository/src/main/java/org/jboss/dna/repository/RepositoryService.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -22,7 +22,6 @@
 package org.jboss.dna.repository;
 
 import java.lang.reflect.InvocationTargetException;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -34,17 +33,14 @@
 import org.jboss.dna.connector.federation.FederationException;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.commands.basic.BasicCompositeCommand;
-import org.jboss.dna.graph.commands.basic.BasicGetChildrenCommand;
-import org.jboss.dna.graph.commands.basic.BasicGetNodeCommand;
-import org.jboss.dna.graph.commands.executor.CommandExecutor;
-import org.jboss.dna.graph.commands.executor.SingleSourceCommandExecutor;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.Node;
+import org.jboss.dna.graph.Subgraph;
 import org.jboss.dna.graph.connectors.RepositorySource;
 import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.NameFactory;
 import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.PathFactory;
+import org.jboss.dna.graph.properties.PathNotFoundException;
 import org.jboss.dna.graph.properties.Property;
 import org.jboss.dna.graph.properties.ValueFactories;
 import org.jboss.dna.graph.properties.ValueFactory;
@@ -184,48 +180,22 @@
             // ------------------------------------------------------------------------------------
             // Read the configuration ...
             // ------------------------------------------------------------------------------------
-            ValueFactories valueFactories = context.getValueFactories();
-            PathFactory pathFactory = valueFactories.getPathFactory();
-            NameFactory nameFactory = valueFactories.getNameFactory();
 
-            // Create a command executor to execute the commands.
-            CommandExecutor executor = new SingleSourceCommandExecutor(context, configurationSourceName, sources);
-
-            // 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
-            Path configurationRoot = this.pathToConfigurationRoot;
+            // Read the configuration and repository source nodes (children under "/dna:sources") ...
+            Graph graph = Graph.create(getConfigurationSourceName(), sources, context);
+            Path pathToSourcesNode = context.getValueFactories().getPathFactory().create(pathToConfigurationRoot, "dna:sources");
             try {
-                Path sourcesNode = pathFactory.create(configurationRoot, nameFactory.create("dna:sources"));
-                BasicGetChildrenCommand getSources = new BasicGetChildrenCommand(sourcesNode);
-                executor.execute(getSources);
-                if (getSources.hasNoError()) {
+                Subgraph sourcesGraph = graph.getSubgraphOfDepth(3).at(pathToSourcesNode);
 
-                    // 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));
-                        }
-                        executor.execute(commands);
-
-                        // Iterate over each source node obtained ...
-                        for (GraphCommand command : commands) {
-                            BasicGetNodeCommand getSourceCommand = (BasicGetNodeCommand)command;
-                            if (getSourceCommand.hasNoError()) {
-                                RepositorySource source = createRepositorySource(getSourceCommand.getPath(),
-                                                                                 getSourceCommand.getPropertiesByName(),
-                                                                                 problems);
-                                if (source != null) sources.addSource(source);
-                            }
-                        }
-                    }
+                // Iterate over each of the children, and create the RepositorySource ...
+                for (Location location : sourcesGraph.getRoot().getChildren()) {
+                    Node sourceNode = sourcesGraph.getNode(location);
+                    sources.addSource(createRepositorySource(location.getPath(), sourceNode.getPropertiesByName(), problems));
                 }
+            } catch (PathNotFoundException e) {
+                // No sources were found, and this is okay!
             } catch (Throwable err) {
-                throw new FederationException(RepositoryI18n.errorStartingRepositoryService.text());
-            } finally {
-                executor.close();
+                throw new FederationException(RepositoryI18n.errorStartingRepositoryService.text(), err);
             }
             this.started.set(true);
         }

Modified: trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -44,14 +44,13 @@
 import org.jboss.dna.connector.inmemory.InMemoryRepositorySource;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.ExecutionContextFactory;
-import org.jboss.dna.graph.commands.basic.BasicGetNodeCommand;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.connectors.BasicExecutionContextFactory;
-import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.PathFactory;
 import org.jboss.dna.graph.properties.PathNotFoundException;
 import org.jboss.dna.graph.properties.Property;
-import org.jboss.dna.graph.util.GraphImporter;
 import org.jboss.dna.jcr.JcrRepository;
 import org.jboss.dna.repository.RepositoryLibrary;
 import org.jboss.dna.repository.RepositoryService;
@@ -147,16 +146,15 @@
         // Normally, these would exist already and would simply be accessed. But in this example, we're going to
         // populate these repositories here by importing from files. First do the configuration repository ...
         String location = this.userInterface.getLocationOfRepositoryFiles();
-        GraphImporter importer = new GraphImporter(sources, context);
-        importer.importXml(location + "/configRepository.xml").into(configSource.getName());
+        Graph.create("Configuration", sources, context).importXmlFrom(location + "/configRepository.xml").into("/");
 
         // Now instantiate the Repository Service ...
         repositoryService = new RepositoryService(sources, configSource.getName(), context);
         repositoryService.getAdministrator().start();
 
         // Now import the conten for two of the other in-memory repositories ...
-        importer.importXml(location + "/cars.xml").into("Cars");
-        importer.importXml(location + "/aircraft.xml").into("Aircraft");
+        Graph.create("Cars", sources, context).importXmlFrom(location + "/cars.xml").into("/");
+        Graph.create("Aircraft", sources, context).importXmlFrom(location + "/aircraft.xml").into("/");
     }
 
     /**
@@ -295,45 +293,36 @@
                     }
                 } catch (javax.jcr.PathNotFoundException e) {
                     return false;
+                } catch (Throwable t) {
+                    t.printStackTrace();
                 } finally {
                     if (session != null) session.logout();
                 }
                 break;
             }
             case DNA: {
-                ExecutionContext context = loginContext != null ? contextFactory.create(loginContext) : contextFactory.create();
-                PathFactory pathFactory = context.getValueFactories().getPathFactory();
-
-                // Get the node submitting a graph command to a repository connection.
-                // (Using commands is a little verbose, but we'll be introducing in the next release
-                // an API that is much easier and concise.)
-                Path path = pathToNode != null ? pathFactory.create(pathToNode) : pathFactory.createRootPath();
-                BasicGetNodeCommand command = new BasicGetNodeCommand(path);
-                RepositoryConnection connection = sources.createConnection(sourceName);
                 try {
-                    connection.execute(context, command);
-                } finally {
-                    if (connection != null) connection.close();
-                }
+                    // Use the DNA Graph API to read the properties and children of the node ...
+                    ExecutionContext context = loginContext != null ? contextFactory.create(loginContext) : contextFactory.create();
+                    Graph graph = Graph.create(sourceName, sources, context);
+                    org.jboss.dna.graph.Node node = graph.getNodeAt(pathToNode);
 
-                // Check whether there's been an error ...
-                if (command.hasError()) {
-                    if (command.getError() instanceof PathNotFoundException) return false;
-                    throw command.getError();
-                }
-
-                // Now populate the properties and children ...
-                if (properties != null) {
-                    for (Property property : command.getProperties()) {
-                        String name = property.getName().getString(context.getNamespaceRegistry());
-                        properties.put(name, property.getValuesAsArray());
+                    if (properties != null) {
+                        // Now copy the properties into the map provided as a method parameter ...
+                        for (Property property : node.getProperties()) {
+                            String name = property.getName().getString(context.getNamespaceRegistry());
+                            properties.put(name, property.getValuesAsArray());
+                        }
                     }
-                }
-                if (children != null) {
-                    for (Path.Segment child : command.getChildren()) {
-                        String name = child.getString(context.getNamespaceRegistry());
-                        children.add(name);
+                    if (children != null) {
+                        // And copy the names of the children into the list provided as a method parameter ...
+                        for (Location child : node.getChildren()) {
+                            String name = child.getPath().getLastSegment().getString(context.getNamespaceRegistry());
+                            children.add(name);
+                        }
                     }
+                } catch (PathNotFoundException e) {
+                    return false;
                 }
                 break;
             }

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepository.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepository.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepository.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -31,11 +31,11 @@
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.connector.federation.executor.FederatingCommandExecutor;
 import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.commands.executor.CommandExecutor;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
 import org.jboss.dna.graph.connectors.RepositorySource;
 import org.jboss.dna.graph.connectors.RepositorySourceListener;
+import org.jboss.dna.graph.requests.processor.RequestProcessor;
 
 /**
  * The component that represents a single federated repository. The federated repository uses a set of {@link RepositorySource
@@ -221,14 +221,14 @@
     }
 
     /**
-     * Called by {@link FederatedRepositoryConnection#execute(ExecutionContext, org.jboss.dna.graph.commands.GraphCommand...)} .
+     * Called by {@link FederatedRepositoryConnection#execute(ExecutionContext, org.jboss.dna.graph.requests.Request)}.
      * 
      * @param context the execution context in which the executor will be run; may not be null
      * @param sourceName the name of the {@link RepositorySource} that is making use of this executor; may not be null or empty
      * @return the executor
      */
-    protected CommandExecutor getExecutor( ExecutionContext context,
-                                           String sourceName ) {
+    protected RequestProcessor getProcessor( ExecutionContext context,
+                                             String sourceName ) {
         FederatedRepositoryConfig config = this.getConfiguration();
         return new FederatingCommandExecutor(context, sourceName, config.getCacheProjection(), config.getDefaultCachePolicy(),
                                              config.getSourceProjections(), getConnectionFactory());

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConnection.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConnection.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositoryConnection.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -27,12 +27,11 @@
 import net.jcip.annotations.ThreadSafe;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.commands.executor.CommandExecutor;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositorySourceException;
 import org.jboss.dna.graph.connectors.RepositorySourceListener;
 import org.jboss.dna.graph.requests.Request;
+import org.jboss.dna.graph.requests.processor.RequestProcessor;
 
 /**
  * @author Randall Hauch
@@ -111,40 +110,29 @@
 
     /**
      * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connectors.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
+     *      org.jboss.dna.graph.requests.Request)
      */
     public void execute( ExecutionContext context,
-                         GraphCommand... commands ) throws RepositorySourceException {
+                         Request request ) throws RepositorySourceException {
         if (!this.repository.isRunning()) {
             throw new RepositorySourceException(FederationI18n.repositoryHasBeenShutDown.text(this.repository.getName()));
         }
-        if (commands == null || commands.length == 0) return;
+        if (request == null) return;
 
-        CommandExecutor executor = this.repository.getExecutor(context, sourceName);
+        RequestProcessor processor = this.repository.getProcessor(context, sourceName);
+        assert processor != null;
         try {
-            assert executor != null;
-            for (GraphCommand command : commands) {
-                executor.execute(command);
-            }
+            processor.process(request);
         } finally {
-            executor.close();
+            processor.close();
         }
     }
 
     /**
      * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.connectors.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
-     *      org.jboss.dna.graph.requests.Request)
      */
-    public void execute( ExecutionContext context,
-                         Request request ) throws RepositorySourceException {
-        // TODO
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
     public void close() {
         try {
             this.repository.removeListener(this.listener.get());

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatedRepositorySource.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -21,7 +21,6 @@
  */
 package org.jboss.dna.connector.federation;
 
-import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
@@ -45,31 +44,22 @@
 import org.jboss.dna.common.collection.SimpleProblems;
 import org.jboss.dna.common.i18n.I18n;
 import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.common.util.Logger;
-import org.jboss.dna.connector.federation.executor.FederatingCommandExecutor;
-import org.jboss.dna.connector.federation.executor.SingleProjectionCommandExecutor;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.ExecutionContextFactory;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.Node;
+import org.jboss.dna.graph.Subgraph;
 import org.jboss.dna.graph.cache.BasicCachePolicy;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.commands.basic.BasicCompositeCommand;
-import org.jboss.dna.graph.commands.basic.BasicGetChildrenCommand;
-import org.jboss.dna.graph.commands.basic.BasicGetNodeCommand;
-import org.jboss.dna.graph.commands.executor.CommandExecutor;
-import org.jboss.dna.graph.commands.executor.LoggingCommandExecutor;
-import org.jboss.dna.graph.commands.executor.NoOpCommandExecutor;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
 import org.jboss.dna.graph.connectors.RepositoryContext;
 import org.jboss.dna.graph.connectors.RepositorySource;
 import org.jboss.dna.graph.connectors.RepositorySourceCapabilities;
 import org.jboss.dna.graph.connectors.RepositorySourceException;
-import org.jboss.dna.graph.properties.InvalidPathException;
-import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.NameFactory;
 import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.PathFactory;
 import org.jboss.dna.graph.properties.Property;
 import org.jboss.dna.graph.properties.ValueFactories;
 import org.jboss.dna.graph.properties.ValueFactory;
@@ -100,7 +90,7 @@
     protected static final String SECURITY_DOMAIN = "securityDomain";
     protected static final String RETRY_LIMIT = "retryLimit";
 
-    public static final String PATH_TO_CONFIGURATION_INFORMATION = "/dna:system/dna:federation";
+    public static final String DNA_FEDERATION_SEGMENT = "dna:federation";
     public static final String DNA_CACHE_SEGMENT = "dna:cache";
     public static final String DNA_PROJECTIONS_SEGMENT = "dna:projections";
     public static final String PROJECTION_RULES_CONFIG_PROPERTY_NAME = "dna:projectionRules";
@@ -273,7 +263,9 @@
     public void setConfigurationSourcePath( String pathInSourceToConfigurationRoot ) {
         if (this.configurationSourcePath == pathInSourceToConfigurationRoot || this.configurationSourcePath != null
             && this.configurationSourcePath.equals(pathInSourceToConfigurationRoot)) return;
-        this.configurationSourcePath = pathInSourceToConfigurationRoot != null ? pathInSourceToConfigurationRoot : DEFAULT_CONFIGURATION_SOURCE_PATH;
+        String path = pathInSourceToConfigurationRoot != null ? pathInSourceToConfigurationRoot : DEFAULT_CONFIGURATION_SOURCE_PATH;
+        // Ensure one leading slash and one trailing slashes ...
+        this.configurationSourcePath = path = ("/" + path).replaceAll("^/+", "/").replaceAll("/+$", "") + "/";
         changeRepositoryConfig();
     }
 
@@ -521,131 +513,57 @@
                                                                                  RepositoryConnectionFactory connectionFactory ) {
         Problems problems = new SimpleProblems();
         ValueFactories valueFactories = context.getValueFactories();
-        PathFactory pathFactory = valueFactories.getPathFactory();
         NameFactory nameFactory = valueFactories.getNameFactory();
         ValueFactory<Long> longFactory = valueFactories.getLongFactory();
-
-        // Create the configuration projection ...
         ProjectionParser projectionParser = ProjectionParser.getInstance();
-        String ruleStr = "/dna:system => " + this.getConfigurationSourcePath();
-        Projection.Rule[] rules = projectionParser.rulesFromStrings(context, ruleStr);
-        Projection configurationProjection = new Projection(this.getConfigurationSourceName(), rules);
 
-        // Create a federating command executor to execute the commands and merge the results into a single set of
-        // commands.
-        final String configurationSourceName = configurationProjection.getSourceName();
-        List<Projection> projections = Collections.singletonList(configurationProjection);
-        CommandExecutor executor = null;
-        if (configurationProjection.getRules().size() == 0) {
-            // There is no projection for the configuration repository, so just use a no-op executor
-            executor = new NoOpCommandExecutor(context, configurationSourceName);
-        } else if (configurationProjection.isSimple()) {
-            // There is just a single projection for the configuration repository, so just use an executor that
-            // translates the paths using the projection
-            executor = new SingleProjectionCommandExecutor(context, configurationSourceName, configurationProjection,
-                                                           connectionFactory);
-        } else {
-            // The configuration repository has more than one projection, so we need to merge the results
-            executor = new FederatingCommandExecutor(context, configurationSourceName, projections, connectionFactory);
-        }
-        // Wrap the executor with a logging executor ...
-        executor = new LoggingCommandExecutor(executor, context.getLogger(getClass()), Logger.Level.DEBUG);
+        // Create a graph to access the configuration ...
+        Graph config = Graph.create(configurationSourceName, connectionFactory, context);
 
-        // The configuration projection (via "executor") will convert this path into a path that exists in the configuration
-        // repository
-        Path configNode = pathFactory.create(PATH_TO_CONFIGURATION_INFORMATION);
+        // Read the federated repositories subgraph (of max depth 4)...
+        Subgraph repositories = config.getSubgraphOfDepth(4).at(getConfigurationSourcePath());
 
-        try {
-            // Get the repository node ...
-            BasicGetNodeCommand getRepository = new BasicGetNodeCommand(configNode);
-            executor.execute(getRepository);
-            if (getRepository.hasError()) {
-                throw new FederationException(FederationI18n.federatedRepositoryCannotBeFound.text(repositoryName));
-            }
+        // Set up the default cache policy by reading the "dna:federation" node ...
+        CachePolicy defaultCachePolicy = null;
+        Node federation = repositories.getNode(DNA_FEDERATION_SEGMENT);
+        if (federation == null) {
+            I18n msg = FederationI18n.requiredNodeDoesNotExistRelativeToNode;
+            throw new FederationException(msg.text(DNA_FEDERATION_SEGMENT, repositories.getLocation().getPath()));
+        }
+        Property timeToLiveProperty = federation.getProperty(nameFactory.create(CACHE_POLICY_TIME_TO_LIVE_CONFIG_PROPERTY_NAME));
+        if (timeToLiveProperty != null && !timeToLiveProperty.isEmpty()) {
+            long timeToCacheInMillis = longFactory.create(timeToLiveProperty.getValues().next());
+            BasicCachePolicy policy = new BasicCachePolicy(timeToCacheInMillis, TimeUnit.MILLISECONDS);
+            defaultCachePolicy = policy.getUnmodifiable();
+        }
 
-            // Get the first child node of the "dna:cache" node, since this represents the source used as the cache ...
-            Path cacheNode = pathFactory.create(configNode, nameFactory.create(DNA_CACHE_SEGMENT));
-            BasicGetChildrenCommand getCacheSource = new BasicGetChildrenCommand(cacheNode);
+        // Read the "dna:cache" and its projection ...
+        String cacheNodePath = DNA_FEDERATION_SEGMENT + "/" + DNA_CACHE_SEGMENT;
+        Node cacheNode = repositories.getNode(cacheNodePath);
+        if (cacheNode == null) {
+            I18n msg = FederationI18n.requiredNodeDoesNotExistRelativeToNode;
+            throw new FederationException(msg.text(cacheNodePath, repositories.getLocation().getPath()));
+        }
+        Projection cacheProjection = null;
+        for (Location cacheProjectionLocation : cacheNode) {
+            Node projection = repositories.getNode(cacheProjectionLocation);
+            cacheProjection = createProjection(context, projectionParser, projection, problems);
+        }
 
-            executor.execute(getCacheSource);
-            if (getCacheSource.hasError() || getCacheSource.getChildren().size() < 1) {
-                I18n msg = FederationI18n.requiredNodeDoesNotExistRelativeToNode;
-                throw new FederationException(msg.text(DNA_CACHE_SEGMENT, configNode));
-            }
-
-            // Add a command to get the projection defining the cache ...
-            Path pathToCacheRegion = pathFactory.create(cacheNode, getCacheSource.getChildren().get(0));
-            BasicGetNodeCommand getCacheRegion = new BasicGetNodeCommand(pathToCacheRegion);
-            executor.execute(getCacheRegion);
-            Projection cacheProjection = createProjection(context,
-                                                          projectionParser,
-                                                          getCacheRegion.getPath(),
-                                                          getCacheRegion.getPropertiesByName(),
-                                                          problems);
-
-            if (getCacheRegion.hasError()) {
-                I18n msg = FederationI18n.requiredNodeDoesNotExistRelativeToNode;
-                throw new FederationException(msg.text(DNA_CACHE_SEGMENT, configNode));
-            }
-
-            // Get the source projections for the repository ...
-            Path projectionsNode = pathFactory.create(configNode, nameFactory.create(DNA_PROJECTIONS_SEGMENT));
-            BasicGetChildrenCommand getProjections = new BasicGetChildrenCommand(projectionsNode);
-
-            executor.execute(getProjections);
-            if (getProjections.hasError()) {
-                I18n msg = FederationI18n.requiredNodeDoesNotExistRelativeToNode;
-                throw new FederationException(msg.text(DNA_PROJECTIONS_SEGMENT, configNode));
-            }
-
-            // Build the commands to get each of the projections (children of the "dna:projections" node) ...
-            List<Projection> sourceProjections = new LinkedList<Projection>();
-            if (getProjections.hasNoError() && !getProjections.getChildren().isEmpty()) {
-                BasicCompositeCommand commands = new BasicCompositeCommand();
-                for (Path.Segment child : getProjections.getChildren()) {
-                    final Path pathToSource = pathFactory.create(projectionsNode, child);
-                    commands.add(new BasicGetNodeCommand(pathToSource));
-                }
-                // Now execute these commands ...
-                executor.execute(commands);
-
-                // Iterate over each region node obtained ...
-                for (GraphCommand command : commands) {
-                    BasicGetNodeCommand getProjectionCommand = (BasicGetNodeCommand)command;
-                    if (getProjectionCommand.hasNoError()) {
-                        Projection projection = createProjection(context,
-                                                                 projectionParser,
-                                                                 getProjectionCommand.getPath(),
-                                                                 getProjectionCommand.getPropertiesByName(),
-                                                                 problems);
-                        if (projection != null) {
-                            Logger logger = context.getLogger(getClass());
-                            if (logger.isTraceEnabled()) {
-                                logger.trace("Adding projection to federated repository {0}: {1}",
-                                             getRepositoryName(),
-                                             projection);
-                            }
-                            sourceProjections.add(projection);
-                        }
-                    }
-                }
-            }
-
-            // Look for the default cache policy ...
-            BasicCachePolicy cachePolicy = new BasicCachePolicy();
-            Property timeToLiveProperty = getRepository.getPropertiesByName().get(nameFactory.create(CACHE_POLICY_TIME_TO_LIVE_CONFIG_PROPERTY_NAME));
-            if (timeToLiveProperty != null && !timeToLiveProperty.isEmpty()) {
-                cachePolicy.setTimeToLive(longFactory.create(timeToLiveProperty.getValues().next()), TimeUnit.MILLISECONDS);
-            }
-            CachePolicy defaultCachePolicy = cachePolicy.isEmpty() ? null : cachePolicy.getUnmodifiable();
-            return new FederatedRepositoryConfig(repositoryName, cacheProjection, sourceProjections, defaultCachePolicy);
-        } catch (InvalidPathException err) {
-            I18n msg = FederationI18n.federatedRepositoryCannotBeFound;
-            throw new FederationException(msg.text(repositoryName));
-        } finally {
-            executor.close();
+        // Read the "dna:projections" and create a projection for each ...
+        String projectionsPath = DNA_FEDERATION_SEGMENT + "/" + DNA_PROJECTIONS_SEGMENT;
+        Node projectionsNode = repositories.getNode(projectionsPath);
+        if (projectionsNode == null) {
+            I18n msg = FederationI18n.requiredNodeDoesNotExistRelativeToNode;
+            throw new FederationException(msg.text(projectionsNode, repositories.getLocation().getPath()));
         }
+        List<Projection> sourceProjections = new LinkedList<Projection>();
+        for (Location location : projectionsNode) {
+            Node projection = repositories.getNode(location);
+            sourceProjections.add(createProjection(context, projectionParser, projection, problems));
+        }
 
+        return new FederatedRepositoryConfig(repositoryName, cacheProjection, sourceProjections, defaultCachePolicy);
     }
 
     /**
@@ -653,25 +571,24 @@
      * 
      * @param context the execution context that should be used to read the configuration; may not be null
      * @param projectionParser the projection rule parser that should be used; may not be null
-     * @param path the path to the node where these properties were found; never null
-     * @param properties the properties; never null
+     * @param node the node where these properties were found; never null
      * @param problems the problems container in which any problems should be reported; never null
      * @return the region instance, or null if it could not be created
      */
     protected Projection createProjection( ExecutionContext context,
                                            ProjectionParser projectionParser,
-                                           Path path,
-                                           Map<Name, Property> properties,
+                                           Node node,
                                            Problems problems ) {
         ValueFactories valueFactories = context.getValueFactories();
         NameFactory nameFactory = valueFactories.getNameFactory();
         ValueFactory<String> stringFactory = valueFactories.getStringFactory();
 
+        Path path = node.getLocation().getPath();
         String sourceName = path.getLastSegment().getName().getLocalName();
 
         // Get the rules ...
         Projection.Rule[] projectionRules = null;
-        Property projectionRulesProperty = properties.get(nameFactory.create(PROJECTION_RULES_CONFIG_PROPERTY_NAME));
+        Property projectionRulesProperty = node.getProperty(nameFactory.create(PROJECTION_RULES_CONFIG_PROPERTY_NAME));
         if (projectionRulesProperty != null && !projectionRulesProperty.isEmpty()) {
             String[] projectionRuleStrs = stringFactory.create(projectionRulesProperty.getValuesAsArray());
             if (projectionRuleStrs != null && projectionRuleStrs.length != 0) {

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederationI18n.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -33,6 +33,7 @@
     public static I18n requiredNodeDoesNotExistRelativeToNode;
     public static I18n propertyIsRequired;
     public static I18n nodeDoesNotExistAtPath;
+    public static I18n nodeDoesNotExistAtLocation;
     public static I18n errorRemovingNodeFromCache;
 
     public static I18n unableToCreateExecutionContext;

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/Contribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -29,11 +29,10 @@
 import java.util.NoSuchElementException;
 import net.jcip.annotations.Immutable;
 import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
-import org.jboss.dna.graph.properties.Path.Segment;
 import org.jboss.dna.graph.properties.basic.JodaDateTime;
 
 /**
@@ -64,47 +63,47 @@
      * Create a contribution of a single property from the named source.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the location in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param property the property from the source; may not be null
      * @return the contribution
      */
     public static Contribution create( String sourceName,
-                                       Path pathInSource,
+                                       Location locationInSource,
                                        DateTime expirationTime,
                                        Property property ) {
         if (property == null) {
             return new EmptyContribution(sourceName, expirationTime);
         }
-        return new OnePropertyContribution(sourceName, pathInSource, expirationTime, property);
+        return new OnePropertyContribution(sourceName, locationInSource, expirationTime, property);
     }
 
     /**
      * Create a contribution of a single child from the named source.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the path in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param child the child from the source; may not be null or empty
      * @return the contribution
      */
     public static Contribution create( String sourceName,
-                                       Path pathInSource,
+                                       Location locationInSource,
                                        DateTime expirationTime,
-                                       Segment child ) {
+                                       Location child ) {
         if (child == null) {
             return new EmptyContribution(sourceName, expirationTime);
         }
-        return new OneChildContribution(sourceName, pathInSource, expirationTime, child);
+        return new OneChildContribution(sourceName, locationInSource, expirationTime, child);
     }
 
     /**
      * Create a contribution of a single child from the named source.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the path in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param child1 the first child from the source; may not be null or empty
@@ -112,18 +111,18 @@
      * @return the contribution
      */
     public static Contribution create( String sourceName,
-                                       Path pathInSource,
+                                       Location locationInSource,
                                        DateTime expirationTime,
-                                       Segment child1,
-                                       Segment child2 ) {
+                                       Location child1,
+                                       Location child2 ) {
         if (child1 != null) {
             if (child2 != null) {
-                return new TwoChildContribution(sourceName, pathInSource, expirationTime, child1, child2);
+                return new TwoChildContribution(sourceName, locationInSource, expirationTime, child1, child2);
             }
-            return new OneChildContribution(sourceName, pathInSource, expirationTime, child1);
+            return new OneChildContribution(sourceName, locationInSource, expirationTime, child1);
         }
         if (child2 != null) {
-            return new OneChildContribution(sourceName, pathInSource, expirationTime, child2);
+            return new OneChildContribution(sourceName, locationInSource, expirationTime, child2);
         }
         return new EmptyContribution(sourceName, expirationTime);
     }
@@ -132,7 +131,7 @@
      * Create a contribution of the supplied properties and children from the named source.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the path in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param properties the properties from the source; may not be null
@@ -140,83 +139,83 @@
      * @return the contribution
      */
     public static Contribution create( String sourceName,
-                                       Path pathInSource,
+                                       Location locationInSource,
                                        DateTime expirationTime,
                                        Collection<Property> properties,
-                                       List<Segment> children ) {
+                                       List<Location> children ) {
         if (properties == null || properties.isEmpty()) {
             // There are no properties ...
             if (children == null || children.isEmpty()) {
                 return new EmptyContribution(sourceName, expirationTime);
             }
             if (children.size() == 1) {
-                return new OneChildContribution(sourceName, pathInSource, expirationTime, children.iterator().next());
+                return new OneChildContribution(sourceName, locationInSource, expirationTime, children.iterator().next());
             }
             if (children.size() == 2) {
-                Iterator<Segment> iter = children.iterator();
-                return new TwoChildContribution(sourceName, pathInSource, expirationTime, iter.next(), iter.next());
+                Iterator<Location> iter = children.iterator();
+                return new TwoChildContribution(sourceName, locationInSource, expirationTime, iter.next(), iter.next());
             }
-            return new MultiChildContribution(sourceName, pathInSource, expirationTime, children);
+            return new MultiChildContribution(sourceName, locationInSource, expirationTime, children);
         }
         // There are some properties ...
         if (children == null || children.isEmpty()) {
             // There are no children ...
             if (properties.size() == 1) {
-                return new OnePropertyContribution(sourceName, pathInSource, expirationTime, properties.iterator().next());
+                return new OnePropertyContribution(sourceName, locationInSource, expirationTime, properties.iterator().next());
             }
             if (properties.size() == 2) {
                 Iterator<Property> iter = properties.iterator();
-                return new TwoPropertyContribution(sourceName, pathInSource, expirationTime, iter.next(), iter.next());
+                return new TwoPropertyContribution(sourceName, locationInSource, expirationTime, iter.next(), iter.next());
             }
             if (properties.size() == 3) {
                 Iterator<Property> iter = properties.iterator();
-                return new ThreePropertyContribution(sourceName, pathInSource, expirationTime, iter.next(), iter.next(),
+                return new ThreePropertyContribution(sourceName, locationInSource, expirationTime, iter.next(), iter.next(),
                                                      iter.next());
             }
-            return new MultiPropertyContribution(sourceName, pathInSource, expirationTime, properties);
+            return new MultiPropertyContribution(sourceName, locationInSource, expirationTime, properties);
         }
         // There are some properties AND some children ...
-        return new NodeContribution(sourceName, pathInSource, expirationTime, properties, children);
+        return new NodeContribution(sourceName, locationInSource, expirationTime, properties, children);
     }
 
     /**
      * Create a placeholder contribution of a single child from the named source.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the path in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param child the child from the source; may not be null or empty
      * @return the contribution
      */
     public static Contribution createPlaceholder( String sourceName,
-                                                  Path pathInSource,
+                                                  Location locationInSource,
                                                   DateTime expirationTime,
-                                                  Segment child ) {
+                                                  Location child ) {
         if (child == null) {
             return new EmptyContribution(sourceName, expirationTime);
         }
-        return new PlaceholderContribution(sourceName, pathInSource, expirationTime, Collections.singletonList(child));
+        return new PlaceholderContribution(sourceName, locationInSource, expirationTime, Collections.singletonList(child));
     }
 
     /**
      * Create a placeholder contribution of the supplied properties and children from the named source.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the path in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param children the children from the source; may not be null or empty
      * @return the contribution
      */
     public static Contribution createPlaceholder( String sourceName,
-                                                  Path pathInSource,
+                                                  Location locationInSource,
                                                   DateTime expirationTime,
-                                                  List<Segment> children ) {
+                                                  List<Location> children ) {
         if (children == null || children.isEmpty()) {
             return new EmptyContribution(sourceName, expirationTime);
         }
-        return new PlaceholderContribution(sourceName, pathInSource, expirationTime, children);
+        return new PlaceholderContribution(sourceName, locationInSource, expirationTime, children);
     }
 
     /**
@@ -225,7 +224,7 @@
     private static final long serialVersionUID = 1L;
 
     protected static final Iterator<Property> EMPTY_PROPERTY_ITERATOR = new EmptyIterator<Property>();
-    protected static final Iterator<Segment> EMPTY_CHILDREN_ITERATOR = new EmptyIterator<Segment>();
+    protected static final Iterator<Location> EMPTY_CHILDREN_ITERATOR = new EmptyIterator<Location>();
 
     private final String sourceName;
     private DateTime expirationTimeInUtc;
@@ -255,11 +254,11 @@
     }
 
     /**
-     * Get the source-specific path of this information.
+     * Get the source-specific location of this information.
      * 
-     * @return the path as known to the source, or null for {@link EmptyContribution}
+     * @return the location as known to the source, or null for {@link EmptyContribution}
      */
-    public abstract Path getPathInSource();
+    public abstract Location getLocationInSource();
 
     /**
      * Determine whether this contribution has expired given the supplied current time.
@@ -317,7 +316,7 @@
      * 
      * @return the children; never null
      */
-    public Iterator<Segment> getChildren() {
+    public Iterator<Location> getChildren() {
         return EMPTY_CHILDREN_ITERATOR;
     }
 
@@ -394,12 +393,11 @@
         if (getChildrenCount() != 0) {
             sb.append("< ");
             boolean first = true;
-            Iterator<Segment> childIter = getChildren();
+            Iterator<Location> childIter = getChildren();
             while (childIter.hasNext()) {
                 if (!first) sb.append(", ");
                 else first = false;
-                Segment child = childIter.next();
-                sb.append(child);
+                sb.append(childIter.next());
             }
             sb.append(" >");
         }

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/EmptyContribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -22,8 +22,8 @@
 package org.jboss.dna.connector.federation.contribution;
 
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
-import org.jboss.dna.graph.properties.Path;
 
 /**
  * A source contribution that is empty. In other words, the source has no contribution to make.
@@ -59,10 +59,10 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.connector.federation.contribution.Contribution#getPathInSource()
+     * @see org.jboss.dna.connector.federation.contribution.Contribution#getLocationInSource()
      */
     @Override
-    public Path getPathInSource() {
+    public Location getLocationInSource() {
         return null;
     }
 

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiChildContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiChildContribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiChildContribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -25,9 +25,8 @@
 import java.util.LinkedList;
 import java.util.List;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Path.Segment;
 
 /**
  * The contribution of a source to the information for a single federated node.
@@ -42,25 +41,25 @@
      */
     private static final long serialVersionUID = 1L;
 
-    private List<Segment> children;
+    private List<Location> children;
 
     /**
      * Create a contribution of children from the source with the supplied name.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the location in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param children the children from the source; may not be null or empty
      */
     public MultiChildContribution( String sourceName,
-                                   Path pathInSource,
+                                   Location locationInSource,
                                    DateTime expirationTime,
-                                   Iterable<Segment> children ) {
-        super(sourceName, pathInSource, expirationTime);
+                                   Iterable<Location> children ) {
+        super(sourceName, locationInSource, expirationTime);
         assert children != null;
-        this.children = new LinkedList<Segment>();
-        for (Segment child : children) {
+        this.children = new LinkedList<Location>();
+        for (Location child : children) {
             if (child != null) this.children.add(child);
         }
         assert this.children.isEmpty() == false;
@@ -73,8 +72,8 @@
      * @see org.jboss.dna.connector.federation.contribution.Contribution#getChildren()
      */
     @Override
-    public Iterator<Segment> getChildren() {
-        return new ImmutableIterator<Segment>(children.iterator());
+    public Iterator<Location> getChildren() {
+        return new ImmutableIterator<Location>(children.iterator());
     }
 
     /**

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -25,9 +25,9 @@
 import java.util.Iterator;
 import java.util.Map;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
 
 /**
@@ -49,16 +49,16 @@
      * Create a contribution of node properties from the source with the supplied name.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the location in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param properties the properties from the source; may not be null
      */
     public MultiPropertyContribution( String sourceName,
-                                      Path pathInSource,
+                                      Location locationInSource,
                                       DateTime expirationTime,
                                       Iterable<Property> properties ) {
-        super(sourceName, pathInSource, expirationTime);
+        super(sourceName, locationInSource, expirationTime);
         assert properties != null;
         this.properties = new HashMap<Name, Property>();
         for (Property property : properties) {

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NodeContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NodeContribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NodeContribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -25,10 +25,9 @@
 import java.util.LinkedList;
 import java.util.List;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
-import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
-import org.jboss.dna.graph.properties.Path.Segment;
 
 /**
  * The contribution of a source to the information for a single federated node.
@@ -43,27 +42,27 @@
      */
     private static final long serialVersionUID = 1L;
 
-    private List<Segment> children;
+    private List<Location> children;
 
     /**
      * Create a contribution of node properties and children from the source with the supplied name.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the location in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param properties the properties from the source; may not be null
      * @param children the children from the source; may not be null or empty
      */
     public NodeContribution( String sourceName,
-                             Path pathInSource,
+                             Location locationInSource,
                              DateTime expirationTime,
                              Iterable<Property> properties,
-                             Iterable<Segment> children ) {
-        super(sourceName, pathInSource, expirationTime, properties);
+                             Iterable<Location> children ) {
+        super(sourceName, locationInSource, expirationTime, properties);
         assert children != null;
-        this.children = new LinkedList<Segment>();
-        for (Segment child : children) {
+        this.children = new LinkedList<Location>();
+        for (Location child : children) {
             if (child != null) this.children.add(child);
         }
         assert this.children.isEmpty() == false;
@@ -76,8 +75,8 @@
      * @see org.jboss.dna.connector.federation.contribution.Contribution#getChildren()
      */
     @Override
-    public Iterator<Segment> getChildren() {
-        return new ImmutableIterator<Segment>(children.iterator());
+    public Iterator<Location> getChildren() {
+        return new ImmutableIterator<Location>(children.iterator());
     }
 
     /**

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NonEmptyContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NonEmptyContribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/NonEmptyContribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -23,8 +23,8 @@
 
 import net.jcip.annotations.Immutable;
 import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
-import org.jboss.dna.graph.properties.Path;
 
 /**
  * The record of a non-empty source contribution from a single location within the source.
@@ -39,32 +39,32 @@
      */
     private static final long serialVersionUID = 1L;
 
-    private final Path pathInSource;
+    private final Location locationInSource;
 
     /**
      * Create a contribution of node properties from the source with the supplied name.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the location in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      */
     protected NonEmptyContribution( String sourceName,
-                                    Path pathInSource,
+                                    Location locationInSource,
                                     DateTime expirationTime ) {
         super(sourceName, expirationTime);
-        assert pathInSource != null;
-        this.pathInSource = pathInSource;
+        assert locationInSource != null;
+        this.locationInSource = locationInSource;
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.connector.federation.contribution.Contribution#getPathInSource()
+     * @see org.jboss.dna.connector.federation.contribution.Contribution#getLocationInSource()
      */
     @Override
-    public Path getPathInSource() {
-        return pathInSource;
+    public Location getLocationInSource() {
+        return locationInSource;
     }
 
     /**
@@ -76,7 +76,7 @@
      */
     @Override
     public int hashCode() {
-        return HashCode.compute(this.getSourceName(), this.getPathInSource());
+        return HashCode.compute(this.getSourceName(), this.getLocationInSource());
     }
 
     /**
@@ -88,7 +88,7 @@
         if (obj instanceof NonEmptyContribution) {
             NonEmptyContribution that = (NonEmptyContribution)obj;
             if (!this.getSourceName().equals(that.getSourceName())) return false;
-            if (!this.getPathInSource().equals(that.getPathInSource())) return false;
+            if (!this.getLocationInSource().equals(that.getLocationInSource())) return false;
             return true;
         }
         return false;

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OneChildContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OneChildContribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OneChildContribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -23,9 +23,8 @@
 
 import java.util.Iterator;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Path.Segment;
 
 /**
  * The record of a source contributing only a single child to a node.
@@ -40,22 +39,22 @@
      */
     private static final long serialVersionUID = 1L;
 
-    private final Segment child;
+    private final Location child;
 
     /**
      * Create a contribution of a single child from the source with the supplied name.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the location in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param child the child contributed from the source; may not be null
      */
     public OneChildContribution( String sourceName,
-                                 Path pathInSource,
+                                 Location locationInSource,
                                  DateTime expirationTime,
-                                 Segment child ) {
-        super(sourceName, pathInSource, expirationTime);
+                                 Location child ) {
+        super(sourceName, locationInSource, expirationTime);
         assert child != null;
         this.child = child;
         if (ContributionStatistics.RECORD) ContributionStatistics.record(0, 1);
@@ -67,8 +66,8 @@
      * @see org.jboss.dna.connector.federation.contribution.Contribution#getChildren()
      */
     @Override
-    public Iterator<Segment> getChildren() {
-        return new OneValueIterator<Segment>(child);
+    public Iterator<Location> getChildren() {
+        return new OneValueIterator<Location>(child);
     }
 
     /**

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OnePropertyContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OnePropertyContribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/OnePropertyContribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -23,9 +23,9 @@
 
 import java.util.Iterator;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
 
 /**
@@ -47,16 +47,16 @@
      * Create a contribution of node properties from the source with the supplied name.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the location in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param property the property from the source; may not be null
      */
     public OnePropertyContribution( String sourceName,
-                                    Path pathInSource,
+                                    Location locationInSource,
                                     DateTime expirationTime,
                                     Property property ) {
-        super(sourceName, pathInSource, expirationTime);
+        super(sourceName, locationInSource, expirationTime);
         assert property != null;
         assert property.isEmpty() == false;
         this.property = property;

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PlaceholderContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PlaceholderContribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/PlaceholderContribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -22,9 +22,8 @@
 package org.jboss.dna.connector.federation.contribution;
 
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Path.Segment;
 
 /**
  * A placeholder contribution needed because of a source's contribution below the specified children.
@@ -43,16 +42,16 @@
      * Create a contribution of children from the source with the supplied name.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the location in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param children the children from the source; may not be null or empty
      */
     public PlaceholderContribution( String sourceName,
-                                    Path pathInSource,
+                                    Location locationInSource,
                                     DateTime expirationTime,
-                                    Iterable<Segment> children ) {
-        super(sourceName, pathInSource, expirationTime, children);
+                                    Iterable<Location> children ) {
+        super(sourceName, locationInSource, expirationTime, children);
     }
 
     /**

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -23,9 +23,9 @@
 
 import java.util.Iterator;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
 
 /**
@@ -49,7 +49,7 @@
      * Create a contribution of node properties from the source with the supplied name.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the location in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param property1 the first property from the source; may not be null
@@ -57,12 +57,12 @@
      * @param property3 the third property from the source; may not be null
      */
     public ThreePropertyContribution( String sourceName,
-                                      Path pathInSource,
+                                      Location locationInSource,
                                       DateTime expirationTime,
                                       Property property1,
                                       Property property2,
                                       Property property3 ) {
-        super(sourceName, pathInSource, expirationTime);
+        super(sourceName, locationInSource, expirationTime);
         assert property1 != null;
         assert property1.isEmpty() == false;
         assert property2 != null;

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoChildContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoChildContribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoChildContribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -23,9 +23,8 @@
 
 import java.util.Iterator;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Path.Segment;
 
 /**
  * The record of a source contributing only two children to a node.
@@ -40,25 +39,25 @@
      */
     private static final long serialVersionUID = 1L;
 
-    private final Segment child1;
-    private final Segment child2;
+    private final Location child1;
+    private final Location child2;
 
     /**
      * Create a contribution of two children from the source with the supplied name.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the path in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param child1 the first child contributed from the source; may not be null
      * @param child2 the second child contributed from the source; may not be null
      */
     public TwoChildContribution( String sourceName,
-                                 Path pathInSource,
+                                 Location locationInSource,
                                  DateTime expirationTime,
-                                 Segment child1,
-                                 Segment child2 ) {
-        super(sourceName, pathInSource, expirationTime);
+                                 Location child1,
+                                 Location child2 ) {
+        super(sourceName, locationInSource, expirationTime);
         assert child1 != null;
         assert child2 != null;
         this.child1 = child1;
@@ -72,8 +71,8 @@
      * @see org.jboss.dna.connector.federation.contribution.Contribution#getChildren()
      */
     @Override
-    public Iterator<Segment> getChildren() {
-        return new TwoValueIterator<Segment>(child1, child2);
+    public Iterator<Location> getChildren() {
+        return new TwoValueIterator<Location>(child1, child2);
     }
 
     /**

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContribution.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContribution.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContribution.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -23,9 +23,9 @@
 
 import java.util.Iterator;
 import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
 
 /**
@@ -48,18 +48,18 @@
      * Create a contribution of node properties from the source with the supplied name.
      * 
      * @param sourceName the name of the source, which may not be null or blank
-     * @param pathInSource the path in the source for this contributed information; may not be null
+     * @param locationInSource the path in the source for this contributed information; may not be null
      * @param expirationTime the time (in UTC) after which this contribution should be considered expired, or null if there is no
      *        expiration time
      * @param property1 the first property from the source; may not be null
      * @param property2 the first property from the source; may not be null
      */
     public TwoPropertyContribution( String sourceName,
-                                    Path pathInSource,
+                                    Location locationInSource,
                                     DateTime expirationTime,
                                     Property property1,
                                     Property property2 ) {
-        super(sourceName, pathInSource, expirationTime);
+        super(sourceName, locationInSource, expirationTime);
         assert property1 != null;
         assert property1.isEmpty() == false;
         assert property2 != null;

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommand.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommand.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommand.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,105 +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.connector.federation.executor;
-
-import org.jboss.dna.graph.commands.ActsOnPath;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.properties.Path;
-
-/**
- * @author Randall Hauch
- * @param <T> the command type
- */
-public class ActsOnProjectedPathCommand<T extends ActsOnPath & GraphCommand> implements ActsOnPath, GraphCommand {
-
-    private final T delegate;
-    private final Path projectedPath;
-
-    protected ActsOnProjectedPathCommand( T delegate,
-                                          Path projectedPath ) {
-        assert delegate != null;
-        assert projectedPath != null;
-        this.delegate = delegate;
-        this.projectedPath = projectedPath;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.ActsOnPath#getPath()
-     */
-    public Path getPath() {
-        return projectedPath;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.GraphCommand#getError()
-     */
-    public Throwable getError() {
-        return delegate.getError();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.GraphCommand#hasError()
-     */
-    public boolean hasError() {
-        return delegate.hasError();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.GraphCommand#hasNoError()
-     */
-    public boolean hasNoError() {
-        return delegate.hasNoError();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.GraphCommand#isCancelled()
-     */
-    public boolean isCancelled() {
-        return delegate.isCancelled();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.GraphCommand#setError(java.lang.Throwable)
-     */
-    public void setError( Throwable error ) {
-        delegate.setError(error);
-    }
-
-    /**
-     * @return delegate
-     */
-    protected T getOriginalCommand() {
-        return delegate;
-    }
-}

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutor.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -34,6 +34,7 @@
 import java.util.concurrent.TimeUnit;
 import net.jcip.annotations.NotThreadSafe;
 import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.common.util.Logger;
 import org.jboss.dna.connector.federation.FederationI18n;
 import org.jboss.dna.connector.federation.Projection;
@@ -45,36 +46,35 @@
 import org.jboss.dna.connector.federation.merge.strategy.SimpleMergeStrategy;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GetChildrenCommand;
-import org.jboss.dna.graph.commands.GetNodeCommand;
-import org.jboss.dna.graph.commands.GetPropertiesCommand;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.commands.NodeConflictBehavior;
-import org.jboss.dna.graph.commands.basic.BasicCreateNodeCommand;
-import org.jboss.dna.graph.commands.basic.BasicGetNodeCommand;
-import org.jboss.dna.graph.commands.executor.AbstractCommandExecutor;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
 import org.jboss.dna.graph.connectors.RepositorySource;
 import org.jboss.dna.graph.connectors.RepositorySourceException;
 import org.jboss.dna.graph.properties.DateTime;
-import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.PathFactory;
 import org.jboss.dna.graph.properties.PathNotFoundException;
 import org.jboss.dna.graph.properties.Property;
-import org.jboss.dna.graph.properties.Path.Segment;
-import org.jboss.dna.graph.properties.basic.BasicSingleValueProperty;
+import org.jboss.dna.graph.requests.CompositeRequest;
+import org.jboss.dna.graph.requests.CopyBranchRequest;
+import org.jboss.dna.graph.requests.CreateNodeRequest;
+import org.jboss.dna.graph.requests.DeleteBranchRequest;
+import org.jboss.dna.graph.requests.MoveBranchRequest;
+import org.jboss.dna.graph.requests.ReadAllChildrenRequest;
+import org.jboss.dna.graph.requests.ReadAllPropertiesRequest;
+import org.jboss.dna.graph.requests.ReadNodeRequest;
+import org.jboss.dna.graph.requests.Request;
+import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
+import org.jboss.dna.graph.requests.processor.RequestProcessor;
 
 /**
  * @author Randall Hauch
  */
 @NotThreadSafe
-public class FederatingCommandExecutor extends AbstractCommandExecutor {
+public class FederatingCommandExecutor extends RequestProcessor {
 
-    private final Name uuidPropertyName;
-    private final Name mergePlanPropertyName;
     private final CachePolicy defaultCachePolicy;
     private final Projection cacheProjection;
     private final List<Projection> sourceProjections;
@@ -127,9 +127,9 @@
                                       CachePolicy defaultCachePolicy,
                                       List<Projection> sourceProjections,
                                       RepositoryConnectionFactory connectionFactory ) {
-        super(context, sourceName);
-        assert sourceProjections != null;
-        assert connectionFactory != null;
+        super(sourceName, context);
+        CheckArg.isNotNull(sourceProjections, "sourceProjections");
+        CheckArg.isNotNull(connectionFactory, "connectionFactory");
         assert cacheProjection != null ? defaultCachePolicy != null : defaultCachePolicy == null;
         this.cacheProjection = cacheProjection;
         this.defaultCachePolicy = defaultCachePolicy;
@@ -137,8 +137,6 @@
         this.connectionFactory = connectionFactory;
         this.logger = context.getLogger(getClass());
         this.connectionsBySourceName = new HashMap<String, RepositoryConnection>();
-        this.uuidPropertyName = context.getValueFactories().getNameFactory().create(DnaLexicon.UUID);
-        this.mergePlanPropertyName = context.getValueFactories().getNameFactory().create(DnaLexicon.MERGE_PLAN);
         this.sourceNames = new HashSet<String>();
         for (Projection projection : this.sourceProjections) {
             this.sourceNames.add(projection.getSourceName());
@@ -180,10 +178,14 @@
         return cacheProjection;
     }
 
+    protected DateTime getCurrentTimeInUtc() {
+        return getExecutionContext().getValueFactories().getDateFactory().createUtc();
+    }
+
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#close()
+     * @see RequestProcessor#close()
      */
     @Override
     public void close() {
@@ -232,65 +234,114 @@
 
     /**
      * {@inheritDoc}
-     * <p>
-     * This class overrides the {@link AbstractCommandExecutor#execute(GetNodeCommand) default behavior} and instead processes the
-     * command in a more efficient manner.
-     * </p>
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.GetNodeCommand)
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadAllChildrenRequest)
      */
     @Override
-    public void execute( GetNodeCommand command ) throws RepositorySourceException {
-        BasicGetNodeCommand nodeInfo = getNode(command.getPath());
+    public void process( ReadAllChildrenRequest request ) {
+        ReadNodeRequest nodeInfo = getNode(request.of());
         if (nodeInfo.hasError()) return;
-        for (Property property : nodeInfo.getProperties()) {
-            command.setProperty(property);
+        for (Location child : nodeInfo.getChildren()) {
+            request.addChild(child);
         }
-        for (Segment child : nodeInfo.getChildren()) {
-            command.addChild(child, nodeInfo.getChildIdentityProperties(child));
-        }
+        request.setActualLocationOfNode(nodeInfo.getActualLocationOfNode());
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.GetPropertiesCommand)
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadAllPropertiesRequest)
      */
     @Override
-    public void execute( GetPropertiesCommand command ) throws RepositorySourceException {
-        BasicGetNodeCommand nodeInfo = getNode(command.getPath());
+    public void process( ReadAllPropertiesRequest request ) {
+        ReadNodeRequest nodeInfo = getNode(request.at());
         if (nodeInfo.hasError()) return;
         for (Property property : nodeInfo.getProperties()) {
-            command.setProperty(property);
+            request.addProperty(property);
         }
+        request.setActualLocationOfNode(nodeInfo.getActualLocationOfNode());
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.GetChildrenCommand)
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadNodeRequest)
      */
     @Override
-    public void execute( GetChildrenCommand command ) throws RepositorySourceException {
-        BasicGetNodeCommand nodeInfo = getNode(command.getPath());
+    public void process( ReadNodeRequest request ) {
+        ReadNodeRequest nodeInfo = getNode(request.at());
         if (nodeInfo.hasError()) return;
-        for (Segment child : nodeInfo.getChildren()) {
-            command.addChild(child, nodeInfo.getChildIdentityProperties(child));
+        for (Property property : nodeInfo.getProperties()) {
+            request.addProperty(property);
         }
+        for (Location child : nodeInfo.getChildren()) {
+            request.addChild(child);
+        }
+        request.setActualLocationOfNode(nodeInfo.getActualLocationOfNode());
     }
 
     /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CopyBranchRequest)
+     */
+    @Override
+    public void process( CopyBranchRequest request ) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CreateNodeRequest)
+     */
+    @Override
+    public void process( CreateNodeRequest request ) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.DeleteBranchRequest)
+     */
+    @Override
+    public void process( DeleteBranchRequest request ) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.MoveBranchRequest)
+     */
+    @Override
+    public void process( MoveBranchRequest request ) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.UpdatePropertiesRequest)
+     */
+    @Override
+    public void process( UpdatePropertiesRequest request ) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
      * Get the node information from the underlying sources or, if possible, from the cache.
      * 
-     * @param path the path of the node to be returned
+     * @param location the location of the node to be returned
      * @return the node information
      * @throws RepositorySourceException
      */
-    protected BasicGetNodeCommand getNode( Path path ) throws RepositorySourceException {
+    protected ReadNodeRequest getNode( Location location ) throws RepositorySourceException {
         // Check the cache first ...
         final ExecutionContext context = getExecutionContext();
         RepositoryConnection cacheConnection = getConnectionToCache();
-        BasicGetNodeCommand fromCache = new BasicGetNodeCommand(path);
+        ReadNodeRequest fromCache = new ReadNodeRequest(location);
         cacheConnection.execute(context, fromCache);
 
         // Look at the cache results from the cache for problems, or if found a plan in the cache look
@@ -308,25 +359,30 @@
             // that already exists in the cache.
             PathNotFoundException notFound = (PathNotFoundException)fromCache.getError();
             Path lowestExistingAncestor = notFound.getLowestAncestorThatDoesExist();
-            Path ancestor = path.getParent();
-
-            if (!ancestor.equals(lowestExistingAncestor)) {
-                // Load the nodes along the path below the existing ancestor, down to (but excluding) the desired path
-                Path pathToLoad = path.getParent();
-                while (!pathToLoad.equals(lowestExistingAncestor)) {
-                    loadContributionsFromSources(pathToLoad, null, contributions); // sourceNames may be null or empty
-                    FederatedNode mergedNode = createFederatedNode(null, pathToLoad, contributions, true);
-                    if (mergedNode == null) {
-                        // No source had a contribution ...
-                        I18n msg = FederationI18n.nodeDoesNotExistAtPath;
-                        fromCache.setError(new PathNotFoundException(path, ancestor, msg.text(path, ancestor)));
-                        return fromCache;
+            if (location.hasPath()) {
+                Path path = location.getPath();
+                Path ancestor = path.getParent();
+                if (!ancestor.equals(lowestExistingAncestor)) {
+                    // Load the nodes along the path below the existing ancestor, down to (but excluding) the desired path
+                    Path pathToLoad = ancestor;
+                    while (!pathToLoad.equals(lowestExistingAncestor)) {
+                        Location locationToLoad = new Location(pathToLoad);
+                        loadContributionsFromSources(locationToLoad, null, contributions); // sourceNames may be null or empty
+                        FederatedNode mergedNode = createFederatedNode(locationToLoad, contributions, true);
+                        if (mergedNode == null) {
+                            // No source had a contribution ...
+                            I18n msg = FederationI18n.nodeDoesNotExistAtPath;
+                            fromCache.setError(new PathNotFoundException(location, ancestor, msg.text(path, ancestor)));
+                            return fromCache;
+                        }
+                        contributions.clear();
+                        // Move to the next child along the path ...
+                        pathToLoad = pathToLoad.getParent();
                     }
-                    contributions.clear();
-                    // Move to the next child along the path ...
-                    pathToLoad = pathToLoad.getParent();
                 }
+
             }
+
             // At this point, all ancestors exist ...
         } else {
             // There is no error, so look for the merge plan ...
@@ -360,22 +416,29 @@
         }
 
         // Get the contributions from the sources given their names ...
-        loadContributionsFromSources(path, sourceNames, contributions); // sourceNames may be null or empty
-        FederatedNode mergedNode = createFederatedNode(fromCache, path, contributions, true);
+        location = fromCache.getActualLocationOfNode();
+        if (location == null) location = fromCache.at(); // not yet in the cache
+        loadContributionsFromSources(location, sourceNames, contributions); // sourceNames may be null or empty
+        FederatedNode mergedNode = createFederatedNode(location, contributions, true);
         if (mergedNode == null) {
             // No source had a contribution ...
-            Path ancestor = path.getParent();
-            I18n msg = FederationI18n.nodeDoesNotExistAtPath;
-            fromCache.setError(new PathNotFoundException(path, ancestor, msg.text(path, ancestor)));
+            if (location.hasPath()) {
+                Path ancestor = location.getPath().getParent();
+                I18n msg = FederationI18n.nodeDoesNotExistAtPath;
+                fromCache.setError(new PathNotFoundException(location, ancestor, msg.text(location, ancestor)));
+                return fromCache;
+            }
+            I18n msg = FederationI18n.nodeDoesNotExistAtLocation;
+            fromCache.setError(new PathNotFoundException(location, null, msg.text(location)));
             return fromCache;
         }
         return mergedNode;
     }
 
-    protected FederatedNode createFederatedNode( BasicGetNodeCommand fromCache,
-                                                 Path path,
+    protected FederatedNode createFederatedNode( Location location,
                                                  List<Contribution> contributions,
                                                  boolean updateCache ) throws RepositorySourceException {
+        assert location != null;
 
         // If there are no contributions from any source ...
         boolean foundNonEmptyContribution = false;
@@ -388,7 +451,7 @@
         }
         if (!foundNonEmptyContribution) return null;
         if (logger.isTraceEnabled()) {
-            logger.trace("Loaded {0} from sources, resulting in these contributions:", path);
+            logger.trace("Loaded {0} from sources, resulting in these contributions:", location);
             int i = 0;
             for (Contribution contribution : contributions) {
                 logger.trace("  {0} {1}", ++i, contribution);
@@ -399,14 +462,19 @@
         ExecutionContext context = getExecutionContext();
         assert context != null;
         UUID uuid = null;
-        if (fromCache != null) {
-            Property uuidProperty = fromCache.getPropertiesByName().get(DnaLexicon.UUID);
-            if (uuidProperty != null && !uuidProperty.isEmpty()) {
-                uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getValues().next());
-            }
+        Property uuidProperty = location.getIdProperty(DnaLexicon.UUID);
+        // If the actual location has no UUID identification property ...
+        if (uuidProperty == null || uuidProperty.isEmpty()) {
+            uuid = context.getValueFactories().getUuidFactory().create();
+            uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, uuid);
+            // Replace the actual location with one that includes the new UUID property ...
+            location = location.with(uuidProperty);
+        } else {
+            assert uuidProperty.isEmpty() == false;
+            uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getValues().next());
         }
-        if (uuid == null) uuid = UUID.randomUUID();
-        FederatedNode mergedNode = new FederatedNode(path, uuid);
+        assert uuid != null;
+        FederatedNode mergedNode = new FederatedNode(location, uuid);
 
         // Merge the results into a single set of results ...
         assert contributions.size() > 0;
@@ -423,21 +491,54 @@
     }
 
     /**
-     * Load the node at the supplied path from the sources with the supplied name, returning the information. This method always
-     * obtains the information from the sources and does not use or update the cache.
+     * Load the node at the supplied location from the sources with the supplied name, returning the information. This method
+     * always obtains the information from the sources and does not use or update the cache.
      * 
-     * @param path the path of the node that is to be loaded
+     * @param location the location of the node that is to be loaded
      * @param sourceNames the names of the sources from which contributions are to be loaded; may be empty or null if all
      *        contributions from all sources are to be loaded
      * @param contributions the list into which the contributions are to be placed
      * @throws RepositorySourceException
      */
-    protected void loadContributionsFromSources( Path path,
+    protected void loadContributionsFromSources( Location location,
                                                  Set<String> sourceNames,
                                                  List<Contribution> contributions ) throws RepositorySourceException {
         // At this point, there is no merge plan, so read information from the sources ...
-        ExecutionContext context = getExecutionContext();
-        PathFactory pathFactory = context.getValueFactories().getPathFactory();
+        final ExecutionContext context = getExecutionContext();
+        final PathFactory pathFactory = context.getValueFactories().getPathFactory();
+
+        // If the location has no path, then we have to submit a request to ALL sources ...
+        if (!location.hasPath()) {
+            for (Projection projection : this.sourceProjections) {
+                final String source = projection.getSourceName();
+                if (sourceNames != null && !sourceNames.contains(source)) continue;
+                final RepositoryConnection sourceConnection = getConnection(projection);
+                if (sourceConnection == null) continue; // No source exists by this name
+                // Get the cached information ...
+                CachePolicy cachePolicy = sourceConnection.getDefaultCachePolicy();
+                if (cachePolicy == null) cachePolicy = this.defaultCachePolicy;
+                DateTime expirationTime = null;
+                if (cachePolicy != null) {
+                    expirationTime = getCurrentTimeInUtc().plus(cachePolicy.getTimeToLive(), TimeUnit.MILLISECONDS);
+                }
+                // Submit the request ...
+                ReadNodeRequest request = new ReadNodeRequest(location);
+                sourceConnection.execute(context, request);
+                if (request.hasError()) continue;
+                DateTime expTime = request.getCachePolicy() == null ? expirationTime : getCurrentTimeInUtc().plus(request.getCachePolicy().getTimeToLive(),
+                                                                                                                  TimeUnit.MILLISECONDS);
+                // Convert the locations of the children (relative to the source) to be relative to this node
+                Contribution contribution = Contribution.create(source,
+                                                                request.getActualLocationOfNode(),
+                                                                expTime,
+                                                                request.getProperties(),
+                                                                request.getChildren());
+                contributions.add(contribution);
+            }
+        }
+
+        // Otherwise, we can do it by path and projections ...
+        Path path = location.getPath();
         for (Projection projection : this.sourceProjections) {
             final String source = projection.getSourceName();
             if (sourceNames != null && !sourceNames.contains(source)) continue;
@@ -458,30 +559,28 @@
                 // use those to figure out the children of the nodes.
                 Contribution contribution = null;
                 List<Path> topLevelPaths = projection.getTopLevelPathsInRepository(pathFactory);
+                Location input = new Location(path);
                 switch (topLevelPaths.size()) {
                     case 0:
                         break;
                     case 1: {
                         Path topLevelPath = topLevelPaths.iterator().next();
                         if (path.isAncestorOf(topLevelPath)) {
-                            assert topLevelPath.size() > path.size();
-                            Path.Segment child = topLevelPath.getSegment(path.size());
-                            contribution = Contribution.createPlaceholder(source, path, expirationTime, child);
+                            Location child = new Location(topLevelPath);
+                            contribution = Contribution.createPlaceholder(source, input, expirationTime, child);
                         }
                         break;
                     }
                     default: {
                         // We assume that the top-level paths do not overlap ...
-                        List<Path.Segment> children = new ArrayList<Path.Segment>(topLevelPaths.size());
+                        List<Location> children = new ArrayList<Location>(topLevelPaths.size());
                         for (Path topLevelPath : topLevelPaths) {
                             if (path.isAncestorOf(topLevelPath)) {
-                                assert topLevelPath.size() > path.size();
-                                Path.Segment child = topLevelPath.getSegment(path.size());
-                                children.add(child);
+                                children.add(new Location(topLevelPath));
                             }
                         }
                         if (children.size() > 0) {
-                            contribution = Contribution.createPlaceholder(source, path, expirationTime, children);
+                            contribution = Contribution.createPlaceholder(source, input, expirationTime, children);
                         }
                     }
                 }
@@ -494,33 +593,33 @@
                 final int numPaths = pathsInSource.size();
                 if (numPaths == 1) {
                     Path pathInSource = pathsInSource.iterator().next();
-                    BasicGetNodeCommand fromSource = new BasicGetNodeCommand(pathInSource);
+                    ReadNodeRequest fromSource = new ReadNodeRequest(new Location(pathInSource));
                     sourceConnection.execute(getExecutionContext(), fromSource);
                     if (!fromSource.hasError()) {
                         Collection<Property> properties = fromSource.getProperties();
-                        List<Segment> children = fromSource.getChildren();
+                        List<Location> children = fromSource.getChildren();
                         DateTime expTime = fromSource.getCachePolicy() == null ? expirationTime : getCurrentTimeInUtc().plus(fromSource.getCachePolicy().getTimeToLive(),
                                                                                                                              TimeUnit.MILLISECONDS);
-                        Contribution contribution = Contribution.create(source, pathInSource, expTime, properties, children);
+                        Location actualLocation = fromSource.getActualLocationOfNode();
+                        Contribution contribution = Contribution.create(source, actualLocation, expTime, properties, children);
                         contributions.add(contribution);
                     }
                 } else {
-                    BasicGetNodeCommand[] fromSourceCommands = new BasicGetNodeCommand[numPaths];
-                    int i = 0;
+                    List<ReadNodeRequest> fromSourceCommands = new ArrayList<ReadNodeRequest>(numPaths);
                     for (Path pathInSource : pathsInSource) {
-                        fromSourceCommands[i++] = new BasicGetNodeCommand(pathInSource);
+                        fromSourceCommands.add(new ReadNodeRequest(new Location(pathInSource)));
                     }
-                    sourceConnection.execute(context, fromSourceCommands);
-                    for (BasicGetNodeCommand fromSource : fromSourceCommands) {
+                    Request request = CompositeRequest.with(fromSourceCommands);
+                    sourceConnection.execute(context, request);
+                    for (ReadNodeRequest fromSource : fromSourceCommands) {
                         if (fromSource.hasError()) continue;
-                        Collection<Property> properties = fromSource.getProperties();
-                        List<Segment> children = fromSource.getChildren();
                         DateTime expTime = fromSource.getCachePolicy() == null ? expirationTime : getCurrentTimeInUtc().plus(fromSource.getCachePolicy().getTimeToLive(),
                                                                                                                              TimeUnit.MILLISECONDS);
+                        List<Location> children = fromSource.getChildren();
                         Contribution contribution = Contribution.create(source,
-                                                                        fromSource.getPath(),
+                                                                        fromSource.getActualLocationOfNode(),
                                                                         expTime,
-                                                                        properties,
+                                                                        fromSource.getProperties(),
                                                                         children);
                         contributions.add(contribution);
                     }
@@ -529,8 +628,8 @@
         }
     }
 
-    protected MergePlan getMergePlan( BasicGetNodeCommand command ) {
-        Property mergePlanProperty = command.getPropertiesByName().get(mergePlanPropertyName);
+    protected MergePlan getMergePlan( ReadNodeRequest request ) {
+        Property mergePlanProperty = request.getPropertiesByName().get(DnaLexicon.MERGE_PLAN);
         if (mergePlanProperty == null || mergePlanProperty.isEmpty()) {
             return null;
         }
@@ -541,23 +640,13 @@
     protected void updateCache( FederatedNode mergedNode ) throws RepositorySourceException {
         final ExecutionContext context = getExecutionContext();
         final RepositoryConnection cacheConnection = getConnectionToCache();
-        final Path path = mergedNode.getPath();
+        final Location path = mergedNode.at();
 
-        NodeConflictBehavior conflictBehavior = NodeConflictBehavior.UPDATE;
-        Collection<Property> properties = new ArrayList<Property>(mergedNode.getPropertiesByName().size() + 1);
-        properties.add(new BasicSingleValueProperty(this.uuidPropertyName, mergedNode.getUuid()));
-        BasicCreateNodeCommand newNode = new BasicCreateNodeCommand(path, properties, conflictBehavior);
-        List<Segment> children = mergedNode.getChildren();
-        GraphCommand[] intoCache = new GraphCommand[1 + children.size()];
-        int i = 0;
-        intoCache[i++] = newNode;
-        List<Property> noProperties = Collections.emptyList();
-        PathFactory pathFactory = context.getValueFactories().getPathFactory();
-        for (Segment child : mergedNode.getChildren()) {
-            newNode = new BasicCreateNodeCommand(pathFactory.create(path, child), noProperties, conflictBehavior);
-            // newNode.setProperty(new BasicSingleValueProperty(this.uuidPropertyName, mergedNode.getUuid()));
-            intoCache[i++] = newNode;
+        List<Request> requests = new ArrayList<Request>();
+        requests.add(new CreateNodeRequest(path, mergedNode.getProperties()));
+        for (Location child : mergedNode.getChildren()) {
+            requests.add(new CreateNodeRequest(child));
         }
-        cacheConnection.execute(context, intoCache);
+        cacheConnection.execute(context, CompositeRequest.with(requests));
     }
 }

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommand.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommand.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommand.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,50 +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.connector.federation.executor;
-
-import org.jboss.dna.graph.commands.CopyBranchCommand;
-import org.jboss.dna.graph.properties.Path;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedCopyBranchCommand extends ActsOnProjectedPathCommand<CopyBranchCommand> implements CopyBranchCommand {
-
-    private final Path newProjectedPath;
-
-    public ProjectedCopyBranchCommand( CopyBranchCommand delegate,
-                                       Path projectedPath,
-                                       Path newProjectedPath ) {
-        super(delegate, projectedPath);
-        assert newProjectedPath != null;
-        this.newProjectedPath = newProjectedPath;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.CopyBranchCommand#getNewPath()
-     */
-    public Path getNewPath() {
-        return newProjectedPath;
-    }
-}

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommand.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommand.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommand.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,51 +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.connector.federation.executor;
-
-import org.jboss.dna.graph.commands.CopyNodeCommand;
-import org.jboss.dna.graph.properties.Path;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedCopyNodeCommand extends ActsOnProjectedPathCommand<CopyNodeCommand> implements CopyNodeCommand {
-
-    private final Path newProjectedPath;
-
-    public ProjectedCopyNodeCommand( CopyNodeCommand delegate,
-                                     Path projectedPath,
-                                     Path newProjectedPath ) {
-        super(delegate, projectedPath);
-        assert newProjectedPath != null;
-        this.newProjectedPath = newProjectedPath;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.CopyNodeCommand#getNewPath()
-     */
-    public Path getNewPath() {
-        return newProjectedPath;
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCreateNodeCommand.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCreateNodeCommand.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedCreateNodeCommand.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,68 +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.connector.federation.executor;
-
-import java.util.Collection;
-import org.jboss.dna.graph.commands.CreateNodeCommand;
-import org.jboss.dna.graph.commands.NodeConflictBehavior;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Property;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedCreateNodeCommand extends ActsOnProjectedPathCommand<CreateNodeCommand> implements CreateNodeCommand {
-
-    public ProjectedCreateNodeCommand( CreateNodeCommand delegate,
-                                       Path projectedPath ) {
-        super(delegate, projectedPath);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.CreateNodeCommand#getConflictBehavior()
-     */
-    public NodeConflictBehavior getConflictBehavior() {
-        return getOriginalCommand().getConflictBehavior();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.CreateNodeCommand#getProperties()
-     */
-    public Collection<Property> getProperties() {
-        return getOriginalCommand().getProperties();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see java.lang.Comparable#compareTo(java.lang.Object)
-     */
-    public int compareTo( CreateNodeCommand that ) {
-        if (this == that) return 0;
-        return this.getPath().compareTo(that.getPath());
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommand.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommand.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommand.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,37 +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.connector.federation.executor;
-
-import org.jboss.dna.graph.commands.DeleteBranchCommand;
-import org.jboss.dna.graph.properties.Path;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedDeleteBranchCommand extends ActsOnProjectedPathCommand<DeleteBranchCommand> implements DeleteBranchCommand {
-
-    public ProjectedDeleteBranchCommand( DeleteBranchCommand delegate,
-                                         Path projectedPath ) {
-        super(delegate, projectedPath);
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommand.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommand.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommand.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,92 +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.connector.federation.executor;
-
-import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GetChildrenCommand;
-import org.jboss.dna.graph.properties.DateTime;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Property;
-import org.jboss.dna.graph.properties.Path.Segment;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedGetChildrenCommand extends ActsOnProjectedPathCommand<GetChildrenCommand> implements GetChildrenCommand {
-
-    /**
-     */
-    private static final long serialVersionUID = 1L;
-
-    public ProjectedGetChildrenCommand( GetChildrenCommand delegate,
-                                        Path projectedPath ) {
-        super(delegate, projectedPath);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.GetChildrenCommand#addChild(org.jboss.dna.graph.properties.Path.Segment,
-     *      org.jboss.dna.graph.properties.Property[])
-     */
-    public void addChild( Segment nameOfChild,
-                          Property... identityProperties ) {
-        getOriginalCommand().addChild(nameOfChild, identityProperties);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.GetChildrenCommand#setNoChildren()
-     */
-    public void setNoChildren() {
-        getOriginalCommand().setNoChildren();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.cache.Cacheable#getCachePolicy()
-     */
-    public CachePolicy getCachePolicy() {
-        return getOriginalCommand().getCachePolicy();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.cache.Cacheable#getTimeLoaded()
-     */
-    public DateTime getTimeLoaded() {
-        return getOriginalCommand().getTimeLoaded();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.cache.Cacheable#setCachePolicy(org.jboss.dna.graph.cache.CachePolicy)
-     */
-    public void setCachePolicy( CachePolicy cachePolicy ) {
-        getOriginalCommand().setCachePolicy(cachePolicy);
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommand.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommand.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommand.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,101 +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.connector.federation.executor;
-
-import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GetNodeCommand;
-import org.jboss.dna.graph.properties.DateTime;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Property;
-import org.jboss.dna.graph.properties.Path.Segment;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedGetNodeCommand extends ActsOnProjectedPathCommand<GetNodeCommand> implements GetNodeCommand {
-
-    /**
-     */
-    private static final long serialVersionUID = 1L;
-
-    public ProjectedGetNodeCommand( GetNodeCommand delegate,
-                                    Path projectedPath ) {
-        super(delegate, projectedPath);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.GetChildrenCommand#addChild(org.jboss.dna.graph.properties.Path.Segment,
-     *      org.jboss.dna.graph.properties.Property[])
-     */
-    public void addChild( Segment nameOfChild,
-                          Property... identityProperties ) {
-        getOriginalCommand().addChild(nameOfChild, identityProperties);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.GetChildrenCommand#setNoChildren()
-     */
-    public void setNoChildren() {
-        getOriginalCommand().setNoChildren();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.cache.Cacheable#getCachePolicy()
-     */
-    public CachePolicy getCachePolicy() {
-        return getOriginalCommand().getCachePolicy();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.cache.Cacheable#getTimeLoaded()
-     */
-    public DateTime getTimeLoaded() {
-        return getOriginalCommand().getTimeLoaded();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.cache.Cacheable#setCachePolicy(org.jboss.dna.graph.cache.CachePolicy)
-     */
-    public void setCachePolicy( CachePolicy cachePolicy ) {
-        getOriginalCommand().setCachePolicy(cachePolicy);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.GetPropertiesCommand#setProperty(org.jboss.dna.graph.properties.Property)
-     */
-    public void setProperty( Property property ) {
-        getOriginalCommand().setProperty(property);
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommand.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommand.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommand.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,81 +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.connector.federation.executor;
-
-import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GetPropertiesCommand;
-import org.jboss.dna.graph.properties.DateTime;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Property;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedGetPropertiesCommand extends ActsOnProjectedPathCommand<GetPropertiesCommand>
-    implements GetPropertiesCommand {
-
-    /**
-     */
-    private static final long serialVersionUID = 1L;
-
-    public ProjectedGetPropertiesCommand( GetPropertiesCommand delegate,
-                                          Path projectedPath ) {
-        super(delegate, projectedPath);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.cache.Cacheable#getCachePolicy()
-     */
-    public CachePolicy getCachePolicy() {
-        return getOriginalCommand().getCachePolicy();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.cache.Cacheable#getTimeLoaded()
-     */
-    public DateTime getTimeLoaded() {
-        return getOriginalCommand().getTimeLoaded();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.cache.Cacheable#setCachePolicy(org.jboss.dna.graph.cache.CachePolicy)
-     */
-    public void setCachePolicy( CachePolicy cachePolicy ) {
-        getOriginalCommand().setCachePolicy(cachePolicy);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.GetPropertiesCommand#setProperty(org.jboss.dna.graph.properties.Property)
-     */
-    public void setProperty( Property property ) {
-        getOriginalCommand().setProperty(property);
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommand.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommand.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommand.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,61 +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.connector.federation.executor;
-
-import org.jboss.dna.graph.commands.MoveBranchCommand;
-import org.jboss.dna.graph.commands.NodeConflictBehavior;
-import org.jboss.dna.graph.properties.Path;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedMoveBranchCommand extends ActsOnProjectedPathCommand<MoveBranchCommand> implements MoveBranchCommand {
-
-    private final Path newProjectedPath;
-
-    public ProjectedMoveBranchCommand( MoveBranchCommand delegate,
-                                       Path projectedPath,
-                                       Path newProjectedPath ) {
-        super(delegate, projectedPath);
-        assert newProjectedPath != null;
-        this.newProjectedPath = newProjectedPath;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.MoveBranchCommand#getConflictBehavior()
-     */
-    public NodeConflictBehavior getConflictBehavior() {
-        return getOriginalCommand().getConflictBehavior();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.MoveBranchCommand#getNewPath()
-     */
-    public Path getNewPath() {
-        return this.newProjectedPath;
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommand.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommand.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommand.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,82 +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.connector.federation.executor;
-
-import java.util.Iterator;
-import org.jboss.dna.graph.commands.RecordBranchCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Property;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedRecordBranchCommand extends ActsOnProjectedPathCommand<RecordBranchCommand> implements RecordBranchCommand {
-
-    public ProjectedRecordBranchCommand( RecordBranchCommand delegate,
-                                         Path projectedPath ) {
-        super(delegate, projectedPath);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.RecordBranchCommand#record(org.jboss.dna.graph.properties.Path, java.lang.Iterable)
-     */
-    public boolean record( Path path,
-                           Iterable<Property> properties ) {
-        path = relativePathFrom(path);
-        return getOriginalCommand().record(path, properties);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.RecordBranchCommand#record(org.jboss.dna.graph.properties.Path, java.util.Iterator)
-     */
-    public boolean record( Path path,
-                           Iterator<Property> properties ) {
-        path = relativePathFrom(path);
-        return getOriginalCommand().record(path, properties);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.RecordBranchCommand#record(org.jboss.dna.graph.properties.Path,
-     *      org.jboss.dna.graph.properties.Property[])
-     */
-    public boolean record( Path path,
-                           Property... properties ) {
-        path = relativePathFrom(path);
-        return getOriginalCommand().record(path, properties);
-    }
-
-    protected Path relativePathFrom( Path path ) {
-        if (path == null) return null;
-        if (path.isAbsolute()) {
-            // The path is absolute, so compute the relative path w/r/t the new path ...
-            path = path.relativeTo(this.getPath());
-        }
-        return path;
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommand.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommand.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommand.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,49 +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.connector.federation.executor;
-
-import java.util.Collection;
-import org.jboss.dna.graph.commands.SetPropertiesCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Property;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedSetPropertiesCommand extends ActsOnProjectedPathCommand<SetPropertiesCommand>
-    implements SetPropertiesCommand {
-
-    public ProjectedSetPropertiesCommand( SetPropertiesCommand delegate,
-                                          Path projectedPath ) {
-        super(delegate, projectedPath);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.ActsOnProperties#getProperties()
-     */
-    public Collection<Property> getProperties() {
-        return getOriginalCommand().getProperties();
-    }
-
-}

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/executor/SingleProjectionCommandExecutor.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -23,19 +23,10 @@
 
 import java.util.Set;
 import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.connector.federation.Projection;
 import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.commands.CopyBranchCommand;
-import org.jboss.dna.graph.commands.CopyNodeCommand;
-import org.jboss.dna.graph.commands.CreateNodeCommand;
-import org.jboss.dna.graph.commands.DeleteBranchCommand;
-import org.jboss.dna.graph.commands.GetChildrenCommand;
-import org.jboss.dna.graph.commands.GetNodeCommand;
-import org.jboss.dna.graph.commands.GetPropertiesCommand;
-import org.jboss.dna.graph.commands.MoveBranchCommand;
-import org.jboss.dna.graph.commands.RecordBranchCommand;
-import org.jboss.dna.graph.commands.SetPropertiesCommand;
-import org.jboss.dna.graph.commands.executor.AbstractCommandExecutor;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
 import org.jboss.dna.graph.connectors.RepositorySource;
@@ -43,12 +34,24 @@
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.PathFactory;
+import org.jboss.dna.graph.properties.PathNotFoundException;
+import org.jboss.dna.graph.properties.Property;
+import org.jboss.dna.graph.requests.CopyBranchRequest;
+import org.jboss.dna.graph.requests.CreateNodeRequest;
+import org.jboss.dna.graph.requests.DeleteBranchRequest;
+import org.jboss.dna.graph.requests.MoveBranchRequest;
+import org.jboss.dna.graph.requests.ReadAllChildrenRequest;
+import org.jboss.dna.graph.requests.ReadAllPropertiesRequest;
+import org.jboss.dna.graph.requests.ReadNodeRequest;
+import org.jboss.dna.graph.requests.Request;
+import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
+import org.jboss.dna.graph.requests.processor.RequestProcessor;
 
 /**
  * @author Randall Hauch
  */
 @NotThreadSafe
-public class SingleProjectionCommandExecutor extends AbstractCommandExecutor {
+public class SingleProjectionCommandExecutor extends RequestProcessor {
 
     private final Projection projection;
     private final PathFactory pathFactory;
@@ -82,7 +85,7 @@
                                             DateTime now,
                                             Projection projection,
                                             RepositoryConnectionFactory connectionFactory ) {
-        super(context, sourceName, now);
+        super(sourceName, context, now);
         assert connectionFactory != null;
         assert projection != null;
         assert projection.getRules().size() == 1;
@@ -103,7 +106,7 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#close()
+     * @see RequestProcessor#close()
      */
     @Override
     public void close() {
@@ -120,128 +123,184 @@
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.GetChildrenCommand)
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadAllChildrenRequest)
      */
     @Override
-    public void execute( GetChildrenCommand command ) throws RepositorySourceException {
-        Path pathInSource = getPathInSource(command.getPath());
-        getConnection().execute(this.getExecutionContext(), new ProjectedGetChildrenCommand(command, pathInSource));
+    public void process( ReadAllChildrenRequest request ) {
+        Location locationInSource = projectIntoSource(request.of());
+        ReadAllChildrenRequest projected = new ReadAllChildrenRequest(locationInSource);
+        getConnection().execute(this.getExecutionContext(), projected);
+        if (projected.hasError()) {
+            return;
+        }
+        for (Location child : projected.getChildren()) {
+            request.addChild(child);
+        }
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.GetPropertiesCommand)
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadAllPropertiesRequest)
      */
     @Override
-    public void execute( GetPropertiesCommand command ) throws RepositorySourceException {
-        Path pathInSource = getPathInSource(command.getPath());
-        getConnection().execute(this.getExecutionContext(), new ProjectedGetPropertiesCommand(command, pathInSource));
+    public void process( ReadAllPropertiesRequest request ) {
+        Location locationInSource = projectIntoSource(request.at());
+        ReadAllPropertiesRequest projected = new ReadAllPropertiesRequest(locationInSource);
+        getConnection().execute(this.getExecutionContext(), projected);
+        if (projected.hasError()) {
+            projectError(projected, request.at(), request);
+            return;
+        }
+        for (Property property : projected.getProperties()) {
+            request.addProperty(property);
+        }
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.GetNodeCommand)
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.ReadNodeRequest)
      */
     @Override
-    public void execute( GetNodeCommand command ) throws RepositorySourceException {
-        Path pathInSource = getPathInSource(command.getPath());
-        getConnection().execute(this.getExecutionContext(), new ProjectedGetNodeCommand(command, pathInSource));
+    public void process( ReadNodeRequest request ) {
+        Location locationInSource = projectIntoSource(request.at());
+        ReadNodeRequest projected = new ReadNodeRequest(locationInSource);
+        getConnection().execute(this.getExecutionContext(), projected);
+        if (projected.hasError()) {
+            projectError(projected, request.at(), request);
+            return;
+        }
+        for (Property property : projected.getProperties()) {
+            request.addProperty(property);
+        }
+        for (Location child : projected.getChildren()) {
+            request.addChild(child);
+        }
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.CreateNodeCommand)
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CreateNodeRequest)
      */
     @Override
-    public void execute( CreateNodeCommand command ) throws RepositorySourceException {
-        Path pathInSource = getPathInSource(command.getPath());
-        getConnection().execute(this.getExecutionContext(), new ProjectedCreateNodeCommand(command, pathInSource));
+    public void process( CreateNodeRequest request ) {
+        Location locationInSource = projectIntoSource(request.at());
+        CreateNodeRequest projected = new CreateNodeRequest(locationInSource, request.properties());
+        getConnection().execute(this.getExecutionContext(), projected);
+        if (projected.hasError()) {
+            projectError(projected, request.at(), request);
+            return;
+        }
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.SetPropertiesCommand)
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.UpdatePropertiesRequest)
      */
     @Override
-    public void execute( SetPropertiesCommand command ) throws RepositorySourceException {
-        Path pathInSource = getPathInSource(command.getPath());
-        getConnection().execute(this.getExecutionContext(), new ProjectedSetPropertiesCommand(command, pathInSource));
+    public void process( UpdatePropertiesRequest request ) {
+        Location locationInSource = projectIntoSource(request.on());
+        UpdatePropertiesRequest projected = new UpdatePropertiesRequest(locationInSource, request.properties());
+        getConnection().execute(this.getExecutionContext(), projected);
+        if (projected.hasError()) {
+            projectError(projected, request.on(), request);
+            return;
+        }
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.DeleteBranchCommand)
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.DeleteBranchRequest)
      */
     @Override
-    public void execute( DeleteBranchCommand command ) throws RepositorySourceException {
-        Path pathInSource = getPathInSource(command.getPath());
-        getConnection().execute(this.getExecutionContext(), new ProjectedDeleteBranchCommand(command, pathInSource));
+    public void process( DeleteBranchRequest request ) {
+        Location locationInSource = projectIntoSource(request.at());
+        DeleteBranchRequest projected = new DeleteBranchRequest(locationInSource);
+        getConnection().execute(this.getExecutionContext(), projected);
+        if (projected.hasError()) {
+            projectError(projected, request.at(), request);
+            return;
+        }
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.MoveBranchCommand)
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.MoveBranchRequest)
      */
     @Override
-    public void execute( MoveBranchCommand command ) throws RepositorySourceException {
-        Path pathInSource = getPathInSource(command.getPath());
-        Path newPathInSource = getPathInSource(command.getNewPath());
-        getConnection().execute(this.getExecutionContext(),
-                                new ProjectedMoveBranchCommand(command, pathInSource, newPathInSource));
+    public void process( MoveBranchRequest request ) {
+        Location fromLocationInSource = projectIntoSource(request.from());
+        Location intoLocationInSource = projectIntoSource(request.into());
+        MoveBranchRequest projected = new MoveBranchRequest(fromLocationInSource, intoLocationInSource);
+        getConnection().execute(this.getExecutionContext(), projected);
+        if (projected.hasError()) {
+            projectError(projected, null, request);
+            return;
+        }
     }
 
     /**
      * {@inheritDoc}
      * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.RecordBranchCommand)
+     * @see org.jboss.dna.graph.requests.processor.RequestProcessor#process(org.jboss.dna.graph.requests.CopyBranchRequest)
      */
     @Override
-    public void execute( RecordBranchCommand command ) throws RepositorySourceException {
-        Path pathInSource = getPathInSource(command.getPath());
-        getConnection().execute(this.getExecutionContext(), new ProjectedRecordBranchCommand(command, pathInSource));
+    public void process( CopyBranchRequest request ) {
+        Location fromLocationInSource = projectIntoSource(request.from());
+        Location intoLocationInSource = projectIntoSource(request.into());
+        CopyBranchRequest projected = new CopyBranchRequest(fromLocationInSource, intoLocationInSource);
+        getConnection().execute(this.getExecutionContext(), projected);
+        if (projected.hasError()) {
+            projectError(projected, null, request);
+            return;
+        }
     }
 
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.CopyBranchCommand)
-     */
-    @Override
-    public void execute( CopyBranchCommand command ) throws RepositorySourceException {
-        Path pathInSource = getPathInSource(command.getPath());
-        Path newPathInSource = getPathInSource(command.getNewPath());
-        getConnection().execute(this.getExecutionContext(),
-                                new ProjectedCopyBranchCommand(command, pathInSource, newPathInSource));
+    protected Location projectIntoSource( Location pathInRepository ) {
+        Path path = pathInRepository.getPath();
+        CheckArg.isNotNull(path, "pathInRepository.getPath()");
+        Set<Path> paths = this.projection.getPathsInSource(path, pathFactory);
+        if (paths.isEmpty()) return null;
+        Path projectedPath = paths.iterator().next();
+        Location location = null;
+        if (pathInRepository.hasIdProperties()) {
+            location = new Location(projectedPath, pathInRepository.getIdProperties());
+        } else {
+            new Location(projectedPath);
+        }
+        return location;
     }
 
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.executor.AbstractCommandExecutor#execute(org.jboss.dna.graph.commands.CopyNodeCommand)
-     */
-    @Override
-    public void execute( CopyNodeCommand command ) throws RepositorySourceException {
-        Path pathInSource = getPathInSource(command.getPath());
-        Path newPathInSource = getPathInSource(command.getNewPath());
-        getConnection().execute(this.getExecutionContext(), new ProjectedCopyNodeCommand(command, pathInSource, newPathInSource));
+    protected Location projectIntoRepository( Location pathInSource ) {
+        Path path = pathInSource.getPath();
+        CheckArg.isNotNull(path, "pathInSource.getPath()");
+        Path projectedPath = this.projection.getPathsInRepository(path, pathFactory).iterator().next();
+        Location location = null;
+        if (pathInSource.hasIdProperties()) {
+            location = new Location(projectedPath, pathInSource.getIdProperties());
+        } else {
+            new Location(projectedPath);
+        }
+        return location;
     }
 
-    protected Path getPathInSource( Path pathInRepository ) {
-        Set<Path> paths = this.projection.getPathsInSource(pathInRepository, pathFactory);
-        if (!paths.isEmpty()) {
-            return paths.iterator().next();
+    protected void projectError( Request original,
+                                 Location originalLocation,
+                                 Request projected ) {
+        Throwable error = original.getError();
+        if (error instanceof PathNotFoundException) {
+            PathNotFoundException pnf = (PathNotFoundException)error;
+            Path lowestExisting = pnf.getLowestAncestorThatDoesExist();
+            if (lowestExisting != null) lowestExisting = projectIntoRepository(new Location(lowestExisting)).getPath();
+            if (originalLocation == null) originalLocation = projectIntoRepository(pnf.getLocation());
+            error = new PathNotFoundException(originalLocation, lowestExisting, pnf.getMessage());
         }
-        return this.projection.getPathsInSource(pathInRepository, pathFactory).iterator().next();
+        projected.setError(error);
     }
 
-    protected Path getPathInRepository( Path pathInSource ) {
-        return this.projection.getPathsInRepository(pathInSource, pathFactory).iterator().next();
-    }
-
 }

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FederatedNode.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FederatedNode.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/FederatedNode.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -22,37 +22,33 @@
 package org.jboss.dna.connector.federation.merge;
 
 import java.util.UUID;
-import org.jboss.dna.graph.commands.CreateNodeCommand;
-import org.jboss.dna.graph.commands.NodeConflictBehavior;
-import org.jboss.dna.graph.commands.basic.BasicGetNodeCommand;
-import org.jboss.dna.graph.properties.Path;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.requests.ReadNodeRequest;
 
 /**
  * An in-memory (and temporary) representation of a federated node and it's merged properties and children.
  * 
  * @author Randall Hauch
  */
-public class FederatedNode extends BasicGetNodeCommand implements CreateNodeCommand {
+public class FederatedNode extends ReadNodeRequest {
 
-    protected static final NodeConflictBehavior DEFAULT_CONFLICT_BEHAVIOR = NodeConflictBehavior.UPDATE;
-
     private static final long serialVersionUID = 1L;
 
     private UUID uuid;
     private MergePlan mergePlan;
-    private NodeConflictBehavior nodeConflictBehavior = DEFAULT_CONFLICT_BEHAVIOR;
 
     /**
      * Create a federated node given the path and UUID.
      * 
-     * @param path the path of the federated node; may not be null
+     * @param location the location of the federated node; may not be null
      * @param uuid the UUID of the federated node; may not be null
      */
-    public FederatedNode( Path path,
+    public FederatedNode( Location location,
                           UUID uuid ) {
-        super(path);
+        super(location);
         assert uuid != null;
         this.uuid = uuid;
+        super.setActualLocationOfNode(location);
     }
 
     /**
@@ -92,21 +88,11 @@
     /**
      * {@inheritDoc}
      * 
-     * @see java.lang.Comparable#compareTo(java.lang.Object)
-     */
-    public int compareTo( CreateNodeCommand that ) {
-        if (this == that) return 0;
-        return this.getPath().compareTo(that.getPath());
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
      * @see java.lang.Object#hashCode()
      */
     @Override
     public int hashCode() {
-        return this.uuid.hashCode();
+        return this.at().hashCode();
     }
 
     /**
@@ -119,7 +105,7 @@
         if (obj == this) return true;
         if (obj instanceof FederatedNode) {
             FederatedNode that = (FederatedNode)obj;
-            if (this.getPath().equals(that.getPath())) return true;
+            if (this.at().equals(that.at())) return true;
             if (this.getUuid().equals(that.getUuid())) return true;
         }
         return false;
@@ -132,25 +118,6 @@
      */
     @Override
     public String toString() {
-        return getPath().toString() + " (" + this.getUuid() + ")";
+        return at().toString();
     }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.commands.CreateNodeCommand#getConflictBehavior()
-     */
-    public NodeConflictBehavior getConflictBehavior() {
-        return this.nodeConflictBehavior;
-    }
-
-    /**
-     * Set the behavior when node conflicts arise.
-     * 
-     * @param nodeConflictBehavior the conflict behavior, or null if the default should be used
-     */
-    public void setConflictBehavior( NodeConflictBehavior nodeConflictBehavior ) {
-        this.nodeConflictBehavior = nodeConflictBehavior != null ? nodeConflictBehavior : DEFAULT_CONFLICT_BEHAVIOR;
-    }
-
 }

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategy.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -23,7 +23,6 @@
 
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.UUID;
 import net.jcip.annotations.ThreadSafe;
 import org.jboss.dna.connector.federation.contribution.Contribution;
@@ -31,11 +30,11 @@
 import org.jboss.dna.connector.federation.merge.MergePlan;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.properties.Name;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.properties.Path;
+import org.jboss.dna.graph.properties.PathFactory;
 import org.jboss.dna.graph.properties.Property;
-import org.jboss.dna.graph.properties.UuidFactory;
 import org.jboss.dna.graph.properties.ValueFormatException;
-import org.jboss.dna.graph.properties.Path.Segment;
 
 /**
  * A merge strategy that is optimized for merging when there is a single contribution.
@@ -45,25 +44,7 @@
 @ThreadSafe
 public class OneContributionMergeStrategy implements MergeStrategy {
 
-    public static final boolean DEFAULT_REUSE_UUID_FROM_CONTRIBUTION = true;
-
-    private boolean useUuidFromContribution = DEFAULT_REUSE_UUID_FROM_CONTRIBUTION;
-
     /**
-     * @return reuseUuidFromContribution
-     */
-    public boolean isContributionUuidUsedForFederatedNode() {
-        return useUuidFromContribution;
-    }
-
-    /**
-     * @param useUuidFromContribution Sets useUuidFromContribution to the specified value.
-     */
-    public void setContributionUuidUsedForFederatedNode( boolean useUuidFromContribution ) {
-        this.useUuidFromContribution = useUuidFromContribution;
-    }
-
-    /**
      * {@inheritDoc}
      * <p>
      * This method only uses the one and only one non-null {@link Contribution} in the <code>contributions</code>.
@@ -81,48 +62,89 @@
         assert contributions.size() > 0;
         Contribution contribution = contributions.get(0);
         assert contribution != null;
-        final boolean findUuid = isContributionUuidUsedForFederatedNode();
+        final PathFactory pathFactory = context.getValueFactories().getPathFactory();
+        final Location location = federatedNode.getActualLocationOfNode();
+
         // Copy the children ...
-        List<Segment> children = federatedNode.getChildren();
-        children.clear();
-        Iterator<Segment> childIterator = contribution.getChildren();
+        Iterator<Location> childIterator = contribution.getChildren();
         while (childIterator.hasNext()) {
-            Segment child = childIterator.next();
-            children.add(child);
+            Location child = translateChildFromSourceToRepository(pathFactory, location, childIterator.next());
+            federatedNode.addChild(child);
         }
+
         // Copy the properties ...
-        Map<Name, Property> properties = federatedNode.getPropertiesByName();
-        properties.clear();
-        UUID uuid = null;
-        UuidFactory uuidFactory = null;
+        Property uuidProperty = null;
+        Property dnaUuidProperty = null;
         Iterator<Property> propertyIterator = contribution.getProperties();
         while (propertyIterator.hasNext()) {
             Property property = propertyIterator.next();
-            if (findUuid && uuid == null && property.getName().getLocalName().equals("uuid")) {
-                if (property.isSingle()) {
-                    if (uuidFactory == null) uuidFactory = context.getValueFactories().getUuidFactory();
-                    try {
-                        uuid = uuidFactory.create(property.getValues().next());
-                    } catch (ValueFormatException e) {
-                        // Ignore conversion exceptions
-                    }
+            federatedNode.addProperty(property);
+            if (property.isSingle()) {
+                if (property.getName().equals(DnaLexicon.UUID) && hasUuidValue(context, property)) {
+                    dnaUuidProperty = property;
+                } else if (property.getName().getLocalName().equals("uuid") && hasUuidValue(context, property)) {
+                    uuidProperty = property;
                 }
-            } else {
-                properties.put(property.getName(), property);
             }
         }
-        // If we found a single "uuid" property whose value is a valid UUID ..
-        if (uuid != null) {
-            // then set the UUID on the federated node ...
+        if (dnaUuidProperty != null) uuidProperty = dnaUuidProperty; // use "dna:uuid" if there is one
+
+        // Look for the UUID property on the properties, and update the federated node ...
+        if (uuidProperty != null && !uuidProperty.isEmpty()) {
+            UUID uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getValues().next());
             federatedNode.setUuid(uuid);
+            if (dnaUuidProperty == null) {
+                uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, uuid); // Use the "dna:uuid" name
+            }
+            federatedNode.setActualLocationOfNode(federatedNode.getActualLocationOfNode().with(uuidProperty));
+        } else {
+            // See if there is a UUID property on the location and update the federated node with it...
+            uuidProperty = federatedNode.getActualLocationOfNode().getIdProperty(DnaLexicon.UUID);
+            if (uuidProperty == null || uuidProperty.isEmpty()) {
+                // Generate a new UUID property and add to the node ...
+                UUID uuid = federatedNode.getUuid();
+                if (uuid == null) {
+                    uuid = context.getValueFactories().getUuidFactory().create();
+                    federatedNode.setUuid(uuid);
+                }
+                uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, uuid);
+            }
+            // Set the UUID as a property ...
+            federatedNode.addProperty(uuidProperty);
         }
-        // Set the UUID as a property ...
-        Property uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, federatedNode.getUuid());
-        properties.put(uuidProperty.getName(), uuidProperty);
 
         // Assign the merge plan ...
         MergePlan mergePlan = MergePlan.create(contributions);
         federatedNode.setMergePlan(mergePlan);
     }
 
+    private boolean hasUuidValue( ExecutionContext context,
+                                  Property property ) {
+        assert property.isSingle();
+        try {
+            context.getValueFactories().getUuidFactory().create(property.getValues().next());
+            return true;
+        } catch (ValueFormatException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Utility method to translate the list of locations of the children so that the locations all are correctly relative to
+     * parent location of the federated node.
+     * 
+     * @param factory the path factory
+     * @param parent the parent of the child
+     * @param childInSource the child to be translated, with a source-specific location
+     * @return the list of locations of each child
+     */
+    protected Location translateChildFromSourceToRepository( PathFactory factory,
+                                                             Location parent,
+                                                             Location childInSource ) {
+        // Convert the locations of the children (relative to the source) to be relative to this node
+        Path parentPath = parent.getPath();
+        if (parentPath == null) return childInSource;
+        Path newPath = factory.create(parentPath, childInSource.getPath().getLastSegment());
+        return childInSource.with(newPath);
+    }
 }

Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategy.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -33,15 +33,13 @@
 import org.jboss.dna.connector.federation.merge.MergePlan;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.properties.IoException;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.PathFactory;
 import org.jboss.dna.graph.properties.Property;
 import org.jboss.dna.graph.properties.PropertyFactory;
-import org.jboss.dna.graph.properties.UuidFactory;
 import org.jboss.dna.graph.properties.ValueComparators;
-import org.jboss.dna.graph.properties.Path.Segment;
 
 /**
  * This merge strategy simply merges all of the contributions' properties and combines the children according to the order of the
@@ -82,79 +80,111 @@
         assert context != null;
         assert contributions != null;
         assert contributions.size() > 0;
-        PathFactory pathFactory = context.getValueFactories().getPathFactory();
-        // Prepare the federated node ...
-        List<Segment> children = federatedNode.getChildren();
-        children.clear();
-        Map<Name, Integer> childNames = new HashMap<Name, Integer>();
-        Map<Name, Property> properties = federatedNode.getPropertiesByName();
+
+        final Location location = federatedNode.getActualLocationOfNode();
+        final boolean isRoot = location.hasPath() && location.getPath().isRoot();
+        final boolean removeDuplicateProperties = isRemoveDuplicateProperties();
+        final PathFactory pathFactory = context.getValueFactories().getPathFactory();
+        final Map<Name, Integer> childNames = new HashMap<Name, Integer>();
+        final Map<Name, Property> properties = federatedNode.getPropertiesByName();
         properties.clear();
-        UUID uuid = null;
-        UuidFactory uuidFactory = null;
-        final boolean removeDuplicateProperties = isRemoveDuplicateProperties();
-        // Iterate over the set of contributions (in order) ...
+
+        // Record the different ID properties from the federated node and (later) from each contribution
+        final Map<Name, Property> idProperties = new HashMap<Name, Property>();
+        for (Property idProperty : location) {
+            idProperties.put(idProperty.getName(), idProperty);
+        }
+
+        // Iterate over each of the contributions (in order) ...
         for (Contribution contribution : contributions) {
+            if (contribution.isEmpty()) continue;
             // If the contribution is a placeholder contribution, then the children should be merged into other children ...
             if (contribution.isPlaceholder()) {
                 // Iterate over the children and add only if there is not already one ...
-                Iterator<Segment> childIterator = contribution.getChildren();
+                Iterator<Location> childIterator = contribution.getChildren();
                 while (childIterator.hasNext()) {
-                    Segment child = childIterator.next();
-                    if (!childNames.containsKey(child.getName())) {
-                        childNames.put(child.getName(), 1);
-                        children.add(pathFactory.createSegment(child.getName()));
+                    Location child = childIterator.next();
+                    Name childName = child.getPath().getLastSegment().getName();
+                    if (!childNames.containsKey(childName)) {
+                        childNames.put(childName, 1);
+                        Path pathToChild = pathFactory.create(location.getPath(), childName);
+                        federatedNode.addChild(new Location(pathToChild));
                     }
                 }
+            } else {
+                // Get the identification properties for each contribution ...
+                Location contributionLocation = contribution.getLocationInSource();
+                for (Property idProperty : contributionLocation) {
+                    // Record the property ...
+                    Property existing = properties.put(idProperty.getName(), idProperty);
+                    if (existing != null) {
+                        // There's already an existing property, so we need to merge them ...
+                        Property merged = merge(existing, idProperty, context.getPropertyFactory(), removeDuplicateProperties);
+                        properties.put(merged.getName(), merged);
+                    }
+                }
 
-            } else {
-                // Copy the children ...
-                Iterator<Segment> childIterator = contribution.getChildren();
+                // Accumulate the children ...
+                Iterator<Location> childIterator = contribution.getChildren();
                 while (childIterator.hasNext()) {
-                    Segment child = childIterator.next();
+                    Location child = childIterator.next();
+                    Name childName = child.getPath().getLastSegment().getName();
                     int index = Path.NO_INDEX;
-                    Integer previous = childNames.put(child.getName(), 1);
+                    Integer previous = childNames.put(childName, 1);
                     if (previous != null) {
                         int previousValue = previous.intValue();
                         // Correct the index in the child name map ...
-                        childNames.put(child.getName(), ++previousValue);
+                        childNames.put(childName, ++previousValue);
                         index = previousValue;
                     }
-                    children.add(pathFactory.createSegment(child.getName(), index));
+                    Path pathToChild = pathFactory.create(location.getPath(), childName, index);
+                    federatedNode.addChild(new Location(pathToChild));
                 }
 
-                // Copy the properties ...
-                Iterator<Property> propertyIterator = contribution.getProperties();
-                while (propertyIterator.hasNext()) {
-                    Property property = propertyIterator.next();
+                // Add in the properties ...
+                Iterator<Property> propertyIter = contribution.getProperties();
+                while (propertyIter.hasNext()) {
+                    Property property = propertyIter.next();
                     // Skip the "uuid" property on all root nodes ...
-                    if (federatedNode.getPath().isRoot() && property.getName().getLocalName().equals("uuid")) continue;
+                    if (isRoot && property.getName().getLocalName().equals("uuid")) continue;
+
+                    // Record the property ...
                     Property existing = properties.put(property.getName(), property);
                     if (existing != null) {
                         // There's already an existing property, so we need to merge them ...
                         Property merged = merge(existing, property, context.getPropertyFactory(), removeDuplicateProperties);
                         properties.put(property.getName(), merged);
                     }
-
-                    if (uuid == null && property.getName().getLocalName().equals("uuid") && property.isSingle()) {
-                        if (uuidFactory == null) uuidFactory = context.getValueFactories().getUuidFactory();
-                        try {
-                            uuid = uuidFactory.create(property.getValues().next());
-                        } catch (IoException e) {
-                            // Ignore conversion exceptions
-                            assert uuid == null;
-                        }
-                    }
                 }
             }
         }
-        // If we found a single "uuid" property whose value is a valid UUID ..
-        if (uuid != null) {
-            // then set the UUID on the federated node ...
-            federatedNode.setUuid(uuid);
+
+        if (idProperties.size() != 0) {
+            // Update the location based upon the merged ID properties ...
+            Location newLocation = new Location(location.getPath(), idProperties.values());
+            federatedNode.setActualLocationOfNode(newLocation);
+
+            // Look for the UUID property on the location, and update the federated node ...
+            Property uuidProperty = idProperties.get(DnaLexicon.UUID);
+            if (uuidProperty != null && !uuidProperty.isEmpty()) {
+                UUID uuid = context.getValueFactories().getUuidFactory().create(uuidProperty.getValues().next());
+                federatedNode.setUuid(uuid);
+
+                // Set the UUID as a property ...
+                properties.put(uuidProperty.getName(), uuidProperty);
+            }
+        } else {
+            // Generate a new UUID property and add to the node ...
+            UUID uuid = federatedNode.getUuid();
+            if (uuid == null) {
+                uuid = context.getValueFactories().getUuidFactory().create();
+                federatedNode.setUuid(uuid);
+            }
+
+            // Set the UUID as a property ...
+            Property uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, uuid);
+            properties.put(uuidProperty.getName(), uuidProperty);
         }
-        // Set the UUID as a property ...
-        Property uuidProperty = context.getPropertyFactory().create(DnaLexicon.UUID, federatedNode.getUuid());
-        properties.put(uuidProperty.getName(), uuidProperty);
 
         // Assign the merge plan ...
         MergePlan mergePlan = MergePlan.create(contributions);
@@ -280,6 +310,67 @@
         public void remove() {
             throw new UnsupportedOperationException();
         }
+    }
 
+    protected static class Child {
+        private final Location location;
+        private final boolean placeholder;
+
+        protected Child( Location location,
+                         boolean placeholder ) {
+            assert location != null;
+            this.location = location;
+            this.placeholder = placeholder;
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            return location.hasIdProperties() ? location.getIdProperties().hashCode() : location.getPath().getLastSegment().getName().hashCode();
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override
+        public boolean equals( Object obj ) {
+            if (obj == this) return true;
+            if (obj instanceof Child) {
+                Child that = (Child)obj;
+                if (this.placeholder && that.placeholder) {
+                    // If both are placeholders, then compare just the name ...
+                    assert this.location.hasPath();
+                    assert that.location.hasPath();
+                    Name thisName = this.location.getPath().getLastSegment().getName();
+                    Name thatName = that.location.getPath().getLastSegment().getName();
+                    return thisName.equals(thatName);
+                }
+                if (location.hasIdProperties() && that.location.hasIdProperties()) {
+                    List<Property> thisIds = location.getIdProperties();
+                    List<Property> thatIds = that.location.getIdProperties();
+                    if (thisIds.size() != thatIds.size()) return false;
+                    return thisIds.containsAll(thatIds);
+                }
+                // One or both do not have identification properties, so delegate to the locations...
+                return this.location.equals(that.location);
+            }
+            return false;
+        }
+
+        /**
+         * {@inheritDoc}
+         * 
+         * @see java.lang.Object#toString()
+         */
+        @Override
+        public String toString() {
+            return location.toString();
+        }
     }
 }

Modified: trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/main/resources/org/jboss/dna/connector/federation/FederationI18n.properties	2008-10-23 18:46:32 UTC (rev 572)
@@ -22,6 +22,7 @@
 requiredNodeDoesNotExistRelativeToNode = The required node {0} does not exist relative to {1}
 propertyIsRequired = The {0} property is required but has no value
 nodeDoesNotExistAtPath = No node exists at {0} (or below {1})
+nodeDoesNotExistAtLocation = No node exists at {0}
 errorRemovingNodeFromCache = Error while removing {0} from cache
 
 unableToCreateExecutionContext = Unable to create ExecutionContext for connection to federated source "{0}" when using security domain "{1}"

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryConnectionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryConnectionTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositoryConnectionTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -30,10 +30,9 @@
 import static org.mockito.Mockito.verify;
 import java.util.concurrent.TimeUnit;
 import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.commands.executor.CommandExecutor;
 import org.jboss.dna.graph.connectors.RepositorySourceException;
 import org.jboss.dna.graph.connectors.RepositorySourceListener;
+import org.jboss.dna.graph.requests.Request;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.MockitoAnnotations;
@@ -80,31 +79,19 @@
     public void shouldFailExecutionIfRepositoryAdminsIsNotStarted() throws Exception {
         stub(repository.isRunning()).toReturn(false);
         ExecutionContext context = mock(ExecutionContext.class);
-        GraphCommand command = mock(GraphCommand.class);
-        connection.execute(context, command);
+        Request request = mock(Request.class);
+        connection.execute(context, request);
     }
 
     @Test
-    public void shouldReturnImmediatelyWhenExecutingNullOrEmptyCommandArray() throws Exception {
+    public void shouldReturnImmediatelyWhenExecutingNullRequest() throws Exception {
         stub(repository.isRunning()).toReturn(true);
         ExecutionContext context = mock(ExecutionContext.class);
-        connection.execute(context, (GraphCommand[])null);
+        connection.execute(context, null);
         verify(repository, times(1)).isRunning();
-        connection.execute(context, new GraphCommand[0]);
-        verify(repository, times(2)).isRunning();
     }
 
     @Test
-    public void shouldSkipNullCommandReferencesWhenExecuting() throws Exception {
-        stub(repository.isRunning()).toReturn(true);
-        ExecutionContext context = mock(ExecutionContext.class);
-        CommandExecutor executor = mock(CommandExecutor.class);
-        stub(repository.getExecutor(context, sourceName)).toReturn(executor);
-        connection.execute(context, new GraphCommand[] {null, null, null});
-        verify(repository, times(1)).isRunning();
-    }
-
-    @Test
     public void shouldAddListenerToRepositoryWhenSetOnConnection() {
         // Old listener is no-op, so it is not removed from repository ...
         RepositorySourceListener listener = mock(RepositorySourceListener.class);

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceIntegrationTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -32,13 +32,14 @@
 import static org.mockito.Mockito.stub;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import java.util.ArrayList;
+import java.util.List;
 import javax.naming.Context;
 import javax.security.auth.callback.CallbackHandler;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.ExecutionContextFactory;
-import org.jboss.dna.graph.commands.basic.BasicGetChildrenCommand;
-import org.jboss.dna.graph.commands.basic.BasicGetPropertiesCommand;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.connectors.BasicExecutionContext;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
@@ -50,6 +51,7 @@
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.PathNotFoundException;
 import org.jboss.dna.graph.properties.Property;
+import org.jboss.dna.graph.requests.ReadNodeRequest;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentMatcher;
@@ -181,10 +183,10 @@
         Path pathObj = context.getValueFactories().getPathFactory().create(path);
         try {
             connection = source.getConnection();
-            BasicGetChildrenCommand command = new BasicGetChildrenCommand(pathObj);
-            connection.execute(context, command);
-            assertThat(command.hasError(), is(true));
-            assertThat(command.getError(), instanceOf(PathNotFoundException.class));
+            ReadNodeRequest request = new ReadNodeRequest(new Location(pathObj));
+            connection.execute(context, request);
+            assertThat(request.hasError(), is(true));
+            assertThat(request.getError(), instanceOf(PathNotFoundException.class));
         } finally {
             if (connection != null) connection.close();
         }
@@ -197,18 +199,28 @@
         Path pathObj = context.getValueFactories().getPathFactory().create(path);
         try {
             connection = source.getConnection();
-            BasicGetChildrenCommand command = new BasicGetChildrenCommand(pathObj);
-            connection.execute(context, command);
-            assertThat(command.hasError(), is(false));
+            ReadNodeRequest request = new ReadNodeRequest(new Location(pathObj));
+            connection.execute(context, request);
+            assertThat(request.hasError(), is(false));
             if (children == null || children.length == 0) {
-                assertThat(command.getChildren().isEmpty(), is(true));
+                assertThat(request.getChildren().isEmpty(), is(true));
             } else {
-                Path.Segment[] segments = new Path.Segment[children.length];
+                // We can't use Location.equals(...), since we're only given the expected paths and the actual
+                // locations may have more than just paths. So, create a list of actual locations that just have paths ...
+                List<Location> actualChildren = request.getChildren();
+                List<Location> actualPathOnlyChildren = new ArrayList<Location>(actualChildren.size());
+                for (Location actualChild : actualChildren) {
+                    actualPathOnlyChildren.add(new Location(actualChild.getPath()));
+                }
+                // Now create the array of expected locations (that each contain only a path) ...
+                Location[] expectedChildren = new Location[children.length];
                 int i = 0;
                 for (String child : children) {
-                    segments[i++] = context.getValueFactories().getPathFactory().createSegment(child);
+                    Path.Segment segment = context.getValueFactories().getPathFactory().createSegment(child);
+                    Path childPath = context.getValueFactories().getPathFactory().create(pathObj, segment);
+                    expectedChildren[i++] = new Location(childPath);
                 }
-                assertThat(command.getChildren(), hasItems(segments));
+                assertThat(actualPathOnlyChildren, hasItems(expectedChildren));
             }
         } finally {
             if (connection != null) connection.close();
@@ -223,11 +235,11 @@
         Path pathObj = context.getValueFactories().getPathFactory().create(path);
         try {
             connection = source.getConnection();
-            BasicGetPropertiesCommand command = new BasicGetPropertiesCommand(pathObj);
-            connection.execute(context, command);
-            assertThat(command.hasError(), is(false));
+            ReadNodeRequest request = new ReadNodeRequest(new Location(pathObj));
+            connection.execute(context, request);
+            assertThat(request.hasError(), is(false));
             Name name = context.getValueFactories().getNameFactory().create(propertyName);
-            Property property = command.getPropertiesByName().get(name);
+            Property property = request.getPropertiesByName().get(name);
             assertThat(property.getValuesAsArray(), is(values));
         } finally {
             if (connection != null) connection.close();

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/FederatedRepositorySourceTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -286,7 +286,7 @@
         assertThat((String)refAttributes.remove(FederatedRepositorySource.RETRY_LIMIT), is(Integer.toString(retryLimit)));
         assertThat((String)refAttributes.remove(FederatedRepositorySource.CONFIGURATION_SOURCE_NAME),
                    is(source.getConfigurationSourceName()));
-        assertThat((String)refAttributes.remove(FederatedRepositorySource.CONFIGURATION_SOURCE_PATH), is("/a/b/c"));
+        assertThat((String)refAttributes.remove(FederatedRepositorySource.CONFIGURATION_SOURCE_PATH), is("/a/b/c/"));
         assertThat((String)refAttributes.remove(FederatedRepositorySource.SECURITY_DOMAIN), is(securityDomain));
         assertThat(refAttributes.isEmpty(), is(true));
 

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiChildContributionTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -30,13 +30,11 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Path.Segment;
-import org.jboss.dna.graph.properties.basic.BasicName;
 import org.jboss.dna.graph.properties.basic.BasicPath;
-import org.jboss.dna.graph.properties.basic.BasicPathSegment;
 import org.jboss.dna.graph.properties.basic.JodaDateTime;
 import org.junit.Before;
 import org.junit.Test;
@@ -55,47 +53,46 @@
     private Path pathInSource;
     private MultiChildContribution contribution;
     private DateTime expiration;
-    private List<Segment> children;
-    private Segment child1;
-    private Segment child2;
-    private Segment child3;
+    private List<Location> children;
+    private Location child1;
+    private Location child2;
+    private Location child3;
 
     @Before
     public void beforeEach() throws Exception {
         sourceName = "some source";
         pathInSource = BasicPath.ROOT;
         expiration = TOMORROW;
-        String nsUri = "http://www.jboss.org/default";
-        child1 = new BasicPathSegment(new BasicName(nsUri, "child1"));
-        child2 = new BasicPathSegment(new BasicName(nsUri, "child2"));
-        child3 = new BasicPathSegment(new BasicName(nsUri, "child3"));
+        child1 = mock(Location.class);
+        child2 = mock(Location.class);
+        child3 = mock(Location.class);
         children = Arrays.asList(child1, child2, child3);
-        contribution = new MultiChildContribution(sourceName, pathInSource, expiration, children);
+        contribution = new MultiChildContribution(sourceName, new Location(pathInSource), expiration, children);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new MultiChildContribution(sourceName, pathInSource, expiration, children);
+        contribution = new MultiChildContribution(sourceName, new Location(pathInSource), expiration, children);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new MultiChildContribution(sourceName, pathInSource, expiration, children);
+        contribution = new MultiChildContribution(sourceName, new Location(pathInSource), expiration, children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullChildren() {
         children = null;
-        contribution = new MultiChildContribution(sourceName, pathInSource, expiration, children);
+        contribution = new MultiChildContribution(sourceName, new Location(pathInSource), expiration, children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowEmptyChildren() {
         children = Collections.emptyList();
-        contribution = new MultiChildContribution(sourceName, pathInSource, expiration, children);
+        contribution = new MultiChildContribution(sourceName, new Location(pathInSource), expiration, children);
     }
 
     @Test
@@ -110,7 +107,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new MultiChildContribution(sourceName, pathInSource, NOW, children);
+        contribution = new MultiChildContribution(sourceName, new Location(pathInSource), NOW, children);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }
@@ -118,7 +115,7 @@
     @Test
     public void shouldHaveChildren() {
         assertThat(contribution.getChildrenCount(), is(3));
-        Iterator<Segment> iter = contribution.getChildren();
+        Iterator<Location> iter = contribution.getChildren();
         assertThat(iter.next(), is(child1));
         assertThat(iter.next(), is(child2));
         assertThat(iter.next(), is(child3));

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/MultiPropertyContributionTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -31,6 +31,7 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
@@ -70,32 +71,32 @@
         property2 = new BasicSingleValueProperty(new BasicName(nsUri, "property2"), "value2");
         property3 = new BasicSingleValueProperty(new BasicName(nsUri, "property3"), "value3");
         properties = Arrays.asList(property1, property2, property3);
-        contribution = new MultiPropertyContribution(sourceName, pathInSource, expiration, properties);
+        contribution = new MultiPropertyContribution(sourceName, new Location(pathInSource), expiration, properties);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new MultiPropertyContribution(sourceName, pathInSource, expiration, properties);
+        contribution = new MultiPropertyContribution(sourceName, new Location(pathInSource), expiration, properties);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new MultiPropertyContribution(sourceName, pathInSource, expiration, properties);
+        contribution = new MultiPropertyContribution(sourceName, new Location(pathInSource), expiration, properties);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullProperties() {
         properties = null;
-        contribution = new MultiPropertyContribution(sourceName, pathInSource, expiration, properties);
+        contribution = new MultiPropertyContribution(sourceName, new Location(pathInSource), expiration, properties);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowEmptyProperties() {
         properties = Collections.emptyList();
-        contribution = new MultiPropertyContribution(sourceName, pathInSource, expiration, properties);
+        contribution = new MultiPropertyContribution(sourceName, new Location(pathInSource), expiration, properties);
     }
 
     @Test
@@ -110,7 +111,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new MultiPropertyContribution(sourceName, pathInSource, NOW, properties);
+        contribution = new MultiPropertyContribution(sourceName, new Location(pathInSource), NOW, properties);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/NodeContributionTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -26,18 +26,18 @@
 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 java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
-import org.jboss.dna.graph.properties.Path.Segment;
 import org.jboss.dna.graph.properties.basic.BasicName;
 import org.jboss.dna.graph.properties.basic.BasicPath;
-import org.jboss.dna.graph.properties.basic.BasicPathSegment;
 import org.jboss.dna.graph.properties.basic.BasicSingleValueProperty;
 import org.jboss.dna.graph.properties.basic.JodaDateTime;
 import org.junit.Before;
@@ -61,10 +61,10 @@
     private Property property1;
     private Property property2;
     private Property property3;
-    private List<Segment> children;
-    private Segment child1;
-    private Segment child2;
-    private Segment child3;
+    private List<Location> children;
+    private Location child1;
+    private Location child2;
+    private Location child3;
 
     @Before
     public void beforeEach() throws Exception {
@@ -76,48 +76,48 @@
         property2 = new BasicSingleValueProperty(new BasicName(nsUri, "property2"), "value2");
         property3 = new BasicSingleValueProperty(new BasicName(nsUri, "property3"), "value3");
         properties = Arrays.asList(property1, property2, property3);
-        child1 = new BasicPathSegment(new BasicName(nsUri, "child1"));
-        child2 = new BasicPathSegment(new BasicName(nsUri, "child2"));
-        child3 = new BasicPathSegment(new BasicName(nsUri, "child3"));
+        child1 = mock(Location.class);
+        child2 = mock(Location.class);
+        child3 = mock(Location.class);
         children = Arrays.asList(child1, child2, child3);
-        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+        contribution = new NodeContribution(sourceName, new Location(pathInSource), expiration, properties, children);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+        contribution = new NodeContribution(sourceName, new Location(pathInSource), expiration, properties, children);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+        contribution = new NodeContribution(sourceName, new Location(pathInSource), expiration, properties, children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullProperties() {
         properties = null;
-        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+        contribution = new NodeContribution(sourceName, new Location(pathInSource), expiration, properties, children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowEmptyProperties() {
         properties = Collections.emptyList();
-        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+        contribution = new NodeContribution(sourceName, new Location(pathInSource), expiration, properties, children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullChildren() {
         children = null;
-        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+        contribution = new NodeContribution(sourceName, new Location(pathInSource), expiration, properties, children);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowEmptyChildren() {
         children = Collections.emptyList();
-        contribution = new NodeContribution(sourceName, pathInSource, expiration, properties, children);
+        contribution = new NodeContribution(sourceName, new Location(pathInSource), expiration, properties, children);
     }
 
     @Test
@@ -132,7 +132,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new NodeContribution(sourceName, pathInSource, NOW, properties, children);
+        contribution = new NodeContribution(sourceName, new Location(pathInSource), NOW, properties, children);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }
@@ -140,7 +140,7 @@
     @Test
     public void shouldHaveChildren() {
         assertThat(contribution.getChildrenCount(), is(3));
-        Iterator<Segment> iter = contribution.getChildren();
+        Iterator<Location> iter = contribution.getChildren();
         assertThat(iter.next(), is(child1));
         assertThat(iter.next(), is(child2));
         assertThat(iter.next(), is(child3));

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OneChildContributionTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -27,13 +27,11 @@
 import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.mock;
 import java.util.Iterator;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Path.Segment;
-import org.jboss.dna.graph.properties.basic.BasicName;
 import org.jboss.dna.graph.properties.basic.BasicPath;
-import org.jboss.dna.graph.properties.basic.BasicPathSegment;
 import org.jboss.dna.graph.properties.basic.JodaDateTime;
 import org.junit.Before;
 import org.junit.Test;
@@ -52,35 +50,34 @@
     private Path pathInSource;
     private OneChildContribution contribution;
     private DateTime expiration;
-    private Segment child1;
+    private Location child1;
 
     @Before
     public void beforeEach() throws Exception {
         sourceName = "some source";
         pathInSource = BasicPath.ROOT;
         expiration = TOMORROW;
-        String nsUri = "http://www.jboss.org/default";
-        child1 = new BasicPathSegment(new BasicName(nsUri, "child1"));
-        contribution = new OneChildContribution(sourceName, pathInSource, expiration, child1);
+        child1 = mock(Location.class);
+        contribution = new OneChildContribution(sourceName, new Location(pathInSource), expiration, child1);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new OneChildContribution(sourceName, pathInSource, expiration, child1);
+        contribution = new OneChildContribution(sourceName, new Location(pathInSource), expiration, child1);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new OneChildContribution(sourceName, pathInSource, expiration, child1);
+        contribution = new OneChildContribution(sourceName, new Location(pathInSource), expiration, child1);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullChildren() {
         child1 = null;
-        contribution = new OneChildContribution(sourceName, pathInSource, expiration, child1);
+        contribution = new OneChildContribution(sourceName, new Location(pathInSource), expiration, child1);
     }
 
     @Test
@@ -95,7 +92,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new OneChildContribution(sourceName, pathInSource, NOW, child1);
+        contribution = new OneChildContribution(sourceName, new Location(pathInSource), NOW, child1);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }
@@ -103,7 +100,7 @@
     @Test
     public void shouldHaveChildren() {
         assertThat(contribution.getChildrenCount(), is(1));
-        Iterator<Segment> iter = contribution.getChildren();
+        Iterator<Location> iter = contribution.getChildren();
         assertThat(iter.next(), is(child1));
         assertThat(iter.hasNext(), is(false));
     }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/OnePropertyContributionTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -29,6 +29,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
@@ -62,26 +63,26 @@
         expiration = TOMORROW;
         String nsUri = "http://www.jboss.org/default";
         property1 = new BasicSingleValueProperty(new BasicName(nsUri, "property1"), "value1");
-        contribution = new OnePropertyContribution(sourceName, pathInSource, expiration, property1);
+        contribution = new OnePropertyContribution(sourceName, new Location(pathInSource), expiration, property1);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new OnePropertyContribution(sourceName, pathInSource, expiration, property1);
+        contribution = new OnePropertyContribution(sourceName, new Location(pathInSource), expiration, property1);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new OnePropertyContribution(sourceName, pathInSource, expiration, property1);
+        contribution = new OnePropertyContribution(sourceName, new Location(pathInSource), expiration, property1);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullFirstProperty() {
         property1 = null;
-        contribution = new OnePropertyContribution(sourceName, pathInSource, expiration, property1);
+        contribution = new OnePropertyContribution(sourceName, new Location(pathInSource), expiration, property1);
     }
 
     @Test
@@ -96,7 +97,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new OnePropertyContribution(sourceName, pathInSource, NOW, property1);
+        contribution = new OnePropertyContribution(sourceName, new Location(pathInSource), NOW, property1);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/ThreePropertyContributionTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -29,6 +29,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
@@ -66,38 +67,44 @@
         property1 = new BasicSingleValueProperty(new BasicName(nsUri, "property1"), "value1");
         property2 = new BasicSingleValueProperty(new BasicName(nsUri, "property2"), "value2");
         property3 = new BasicSingleValueProperty(new BasicName(nsUri, "property3"), "value3");
-        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+        contribution = new ThreePropertyContribution(sourceName, new Location(pathInSource), expiration, property1, property2,
+                                                     property3);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+        contribution = new ThreePropertyContribution(sourceName, new Location(pathInSource), expiration, property1, property2,
+                                                     property3);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+        contribution = new ThreePropertyContribution(sourceName, new Location(pathInSource), expiration, property1, property2,
+                                                     property3);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullFirstProperty() {
         property1 = null;
-        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+        contribution = new ThreePropertyContribution(sourceName, new Location(pathInSource), expiration, property1, property2,
+                                                     property3);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullSecondProperty() {
         property2 = null;
-        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+        contribution = new ThreePropertyContribution(sourceName, new Location(pathInSource), expiration, property1, property2,
+                                                     property3);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullThirdProperty() {
         property3 = null;
-        contribution = new ThreePropertyContribution(sourceName, pathInSource, expiration, property1, property2, property3);
+        contribution = new ThreePropertyContribution(sourceName, new Location(pathInSource), expiration, property1, property2,
+                                                     property3);
     }
 
     @Test
@@ -112,7 +119,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new ThreePropertyContribution(sourceName, pathInSource, NOW, property1, property2, property3);
+        contribution = new ThreePropertyContribution(sourceName, new Location(pathInSource), NOW, property1, property2, property3);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoChildContributionTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -27,13 +27,11 @@
 import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.mock;
 import java.util.Iterator;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Path.Segment;
-import org.jboss.dna.graph.properties.basic.BasicName;
 import org.jboss.dna.graph.properties.basic.BasicPath;
-import org.jboss.dna.graph.properties.basic.BasicPathSegment;
 import org.jboss.dna.graph.properties.basic.JodaDateTime;
 import org.junit.Before;
 import org.junit.Test;
@@ -52,43 +50,42 @@
     private Path pathInSource;
     private TwoChildContribution contribution;
     private DateTime expiration;
-    private Segment child1;
-    private Segment child2;
+    private Location child1;
+    private Location child2;
 
     @Before
     public void beforeEach() throws Exception {
         sourceName = "some source";
         pathInSource = BasicPath.ROOT;
         expiration = TOMORROW;
-        String nsUri = "http://www.jboss.org/default";
-        child1 = new BasicPathSegment(new BasicName(nsUri, "child1"));
-        child2 = new BasicPathSegment(new BasicName(nsUri, "child1"));
-        contribution = new TwoChildContribution(sourceName, pathInSource, expiration, child1, child2);
+        child1 = mock(Location.class);
+        child2 = mock(Location.class);
+        contribution = new TwoChildContribution(sourceName, new Location(pathInSource), expiration, child1, child2);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new TwoChildContribution(sourceName, pathInSource, expiration, child1, child2);
+        contribution = new TwoChildContribution(sourceName, new Location(pathInSource), expiration, child1, child2);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new TwoChildContribution(sourceName, pathInSource, expiration, child1, child2);
+        contribution = new TwoChildContribution(sourceName, new Location(pathInSource), expiration, child1, child2);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullFirstChild() {
         child1 = null;
-        contribution = new TwoChildContribution(sourceName, pathInSource, expiration, child1, child2);
+        contribution = new TwoChildContribution(sourceName, new Location(pathInSource), expiration, child1, child2);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullSecondChild() {
         child2 = null;
-        contribution = new TwoChildContribution(sourceName, pathInSource, expiration, child1, child2);
+        contribution = new TwoChildContribution(sourceName, new Location(pathInSource), expiration, child1, child2);
     }
 
     @Test
@@ -103,7 +100,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new TwoChildContribution(sourceName, pathInSource, NOW, child1, child2);
+        contribution = new TwoChildContribution(sourceName, new Location(pathInSource), NOW, child1, child2);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }
@@ -111,7 +108,7 @@
     @Test
     public void shouldHaveChildren() {
         assertThat(contribution.getChildrenCount(), is(2));
-        Iterator<Segment> iter = contribution.getChildren();
+        Iterator<Location> iter = contribution.getChildren();
         assertThat(iter.next(), is(child1));
         assertThat(iter.next(), is(child2));
         assertThat(iter.hasNext(), is(false));

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/contribution/TwoPropertyContributionTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -29,6 +29,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.DateTime;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.Property;
@@ -64,32 +65,32 @@
         String nsUri = "http://www.jboss.org/default";
         property1 = new BasicSingleValueProperty(new BasicName(nsUri, "property1"), "value1");
         property2 = new BasicSingleValueProperty(new BasicName(nsUri, "property2"), "value2");
-        contribution = new TwoPropertyContribution(sourceName, pathInSource, expiration, property1, property2);
+        contribution = new TwoPropertyContribution(sourceName, new Location(pathInSource), expiration, property1, property2);
     }
 
     @Test
     public void shouldAllowNullExpiration() {
         expiration = null;
-        contribution = new TwoPropertyContribution(sourceName, pathInSource, expiration, property1, property2);
+        contribution = new TwoPropertyContribution(sourceName, new Location(pathInSource), expiration, property1, property2);
         assertThat(contribution.getExpirationTimeInUtc(), is(nullValue()));
     }
 
     @Test( expected = IllegalArgumentException.class )
     public void shouldNotAllowExpirationTimeIfNotInUtcTime() {
         expiration = new JodaDateTime(System.currentTimeMillis(), "CST");
-        contribution = new TwoPropertyContribution(sourceName, pathInSource, expiration, property1, property2);
+        contribution = new TwoPropertyContribution(sourceName, new Location(pathInSource), expiration, property1, property2);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullFirstProperty() {
         property1 = null;
-        contribution = new TwoPropertyContribution(sourceName, pathInSource, expiration, property1, property2);
+        contribution = new TwoPropertyContribution(sourceName, new Location(pathInSource), expiration, property1, property2);
     }
 
     @Test( expected = AssertionError.class )
     public void shouldNotAllowNullSecondProperty() {
         property2 = null;
-        contribution = new TwoPropertyContribution(sourceName, pathInSource, expiration, property1, property2);
+        contribution = new TwoPropertyContribution(sourceName, new Location(pathInSource), expiration, property1, property2);
     }
 
     @Test
@@ -104,7 +105,7 @@
 
     @Test
     public void shouldNotBeExpiredIfExpirationIsInTheFuture() {
-        contribution = new TwoPropertyContribution(sourceName, pathInSource, NOW, property1, property2);
+        contribution = new TwoPropertyContribution(sourceName, new Location(pathInSource), NOW, property1, property2);
         assertThat(contribution.isExpired(YESTERDAY), is(false));
         assertThat(contribution.isExpired(TOMORROW), is(true));
     }

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommandTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommandTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ActsOnProjectedPathCommandTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,101 +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.connector.federation.executor;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import org.jboss.dna.graph.commands.GetNodeCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class ActsOnProjectedPathCommandTest {
-
-    private ActsOnProjectedPathCommand<GetNodeCommand> command;
-    @Mock
-    private GetNodeCommand wrapped;
-    @Mock
-    private Path projectedPath;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        command = new ActsOnProjectedPathCommand<GetNodeCommand>(wrapped, projectedPath);
-    }
-
-    @Test
-    public void shouldReturnProjectedPath() {
-        assertThat(command.getPath(), is(sameInstance(projectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-    @Test
-    public void shouldReturnErrorFromWrappedCommands() {
-        Throwable error = mock(Throwable.class);
-        stub(wrapped.getError()).toReturn(error);
-        assertThat(command.getError(), is(error));
-        verify(wrapped).getError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForError() {
-        assertThat(command.hasError(), is(false));
-        verify(wrapped).hasError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForNoError() {
-        stub(wrapped.hasNoError()).toReturn(true);
-        assertThat(command.hasNoError(), is(true));
-        verify(wrapped).hasNoError();
-    }
-
-    @Test
-    public void shouldSetErrorOnWrappedCommand() {
-        Throwable error = mock(Throwable.class);
-        command.setError(error);
-        verify(wrapped).setError(error);
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForCancellation() {
-        stub(wrapped.isCancelled()).toReturn(true);
-        assertThat(command.isCancelled(), is(true));
-        verify(wrapped).isCancelled();
-    }
-
-    @Test
-    public void shouldReturnWrappedCommandAsOriginalCommand() {
-        assertThat(command.getOriginalCommand(), is(sameInstance(wrapped)));
-    }
-
-}

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutorTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutorTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/FederatingCommandExecutorTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -34,6 +34,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
@@ -41,6 +42,7 @@
 import org.jboss.dna.connector.federation.ProjectionParser;
 import org.jboss.dna.connector.federation.contribution.Contribution;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.cache.BasicCachePolicy;
 import org.jboss.dna.graph.cache.CachePolicy;
 import org.jboss.dna.graph.connectors.BasicExecutionContext;
@@ -127,35 +129,35 @@
         SimpleRepository.shutdownAll();
     }
 
-    @Test( expected = AssertionError.class )
+    @Test( expected = IllegalArgumentException.class )
     public void shouldFailWhenExecutionContextIsNull() {
         context = null;
         executor = new FederatingCommandExecutor(context, sourceName, cacheProjection, cachePolicy, sourceProjections,
                                                  connectionFactory);
     }
 
-    @Test( expected = AssertionError.class )
+    @Test( expected = IllegalArgumentException.class )
     public void shouldFailWhenSourceNameIsNull() {
         sourceName = null;
         executor = new FederatingCommandExecutor(context, sourceName, cacheProjection, cachePolicy, sourceProjections,
                                                  connectionFactory);
     }
 
-    @Test( expected = AssertionError.class )
+    @Test( expected = IllegalArgumentException.class )
     public void shouldFailWhenSourceNameIsEmpty() {
         sourceName = "";
         executor = new FederatingCommandExecutor(context, sourceName, cacheProjection, cachePolicy, sourceProjections,
                                                  connectionFactory);
     }
 
-    @Test( expected = AssertionError.class )
+    @Test( expected = IllegalArgumentException.class )
     public void shouldFailWhenSourceNameIsBlank() {
         sourceName = "   ";
         executor = new FederatingCommandExecutor(context, sourceName, cacheProjection, cachePolicy, sourceProjections,
                                                  connectionFactory);
     }
 
-    @Test( expected = AssertionError.class )
+    @Test( expected = IllegalArgumentException.class )
     public void shouldFailWhenConnectionFactoryIsNull() {
         connectionFactory = null;
         executor = new FederatingCommandExecutor(context, sourceName, cacheProjection, cachePolicy, sourceProjections,
@@ -253,20 +255,35 @@
     public void shouldLoadContributionsForRootNodeFromSources() throws Exception {
         Path path = pathFactory.createRootPath();
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(path, null, contributions);
+        executor.loadContributionsFromSources(new Location(path), null, contributions);
 
         assertThat(contributions.size(), is(3)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
         assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
         assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
 
-        Path.Segment aSeg = pathFactory.createSegment("a");
-        Path.Segment bSeg = pathFactory.createSegment("b");
-        assertThat(contributions.get(0).getChildren(), hasItems(aSeg, bSeg));
-        assertThat(contributions.get(1).getChildren(), hasItems(aSeg));
+        Location childA = new Location(pathFactory.create(path, "a"));
+        Location childB = new Location(pathFactory.create(path, "b"));
+        assertThat(contributions.get(0).getChildren(), hasItems(childA, childB));
+        assertThat(contributions.get(1).getChildren(), hasItems(childA));
         assertThat(contributions.get(2).getChildrenCount(), is(0));
     }
 
+    protected void hasChildren( Contribution contribution,
+                                String... childNames ) {
+        Location location = contribution.getLocationInSource();
+        Iterator<Location> iter = contribution.getChildren();
+        for (String childName : childNames) {
+            Path expectedChildPath = context.getValueFactories().getPathFactory().create(location.getPath(), childName);
+            Location expectedChild = new Location(expectedChildPath);
+            Location next = iter.next();
+            if (!next.isSame(expectedChild)) {
+                assertThat(next, is(expectedChild));
+            }
+        }
+        assertThat(iter.hasNext(), is(false));
+    }
+
     @Test
     public void shouldLoadContributionsForNonRootNodeWithOneContributionFromSources() throws Exception {
         // Set up the content of source 3
@@ -278,33 +295,29 @@
 
         Path path = pathFactory.create("/x/y"); // from source 3
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(path, null, contributions);
+        executor.loadContributionsFromSources(new Location(path), null, contributions);
 
         assertThat(contributions.size(), is(3)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
         assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
         assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
 
-        Path.Segment child1 = pathFactory.createSegment("zA");
-        Path.Segment child2 = pathFactory.createSegment("zB");
-        Path.Segment child3 = pathFactory.createSegment("zC");
-        assertThat(contributions.get(0).isEmpty(), is(true));
-        assertThat(contributions.get(1).isEmpty(), is(true));
-        assertThat(contributions.get(2).getChildren(), hasItems(child1, child2, child3));
+        hasChildren(contributions.get(0));
+        hasChildren(contributions.get(1));
+        hasChildren(contributions.get(2), "zA", "zB", "zC");
 
         path = pathFactory.create("/x"); // from source 3
         contributions.clear();
-        executor.loadContributionsFromSources(path, null, contributions);
+        executor.loadContributionsFromSources(new Location(path), null, contributions);
 
         assertThat(contributions.size(), is(3)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
         assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
         assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
 
-        child1 = pathFactory.createSegment("y");
-        assertThat(contributions.get(0).isEmpty(), is(true));
-        assertThat(contributions.get(1).isEmpty(), is(true));
-        assertThat(contributions.get(2).getChildren(), hasItems(child1));
+        hasChildren(contributions.get(0));
+        hasChildren(contributions.get(1));
+        hasChildren(contributions.get(2), "y");
     }
 
     @Test
@@ -337,33 +350,27 @@
 
         Path path = pathFactory.create("/b"); // from source 2 and source 3
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(path, null, contributions);
+        executor.loadContributionsFromSources(new Location(path), null, contributions);
 
         assertThat(contributions.size(), is(3)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
         assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
         assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
 
-        Path.Segment child1 = pathFactory.createSegment("pA");
-        Path.Segment child2 = pathFactory.createSegment("pB");
-        Path.Segment child3 = pathFactory.createSegment("pC");
-        Path.Segment child4 = pathFactory.createSegment("by");
-        assertThat(contributions.get(0).getChildren(), hasItems(child1, child2, child3));
-        assertThat(contributions.get(1).isEmpty(), is(true));
-        assertThat(contributions.get(2).getChildren(), hasItems(child4));
+        hasChildren(contributions.get(0), "pA", "pB", "pC");
+        hasChildren(contributions.get(1));
+        hasChildren(contributions.get(2), "by");
 
         path = pathFactory.create("/b/by"); // from source 3
         contributions.clear();
-        executor.loadContributionsFromSources(path, null, contributions);
+        executor.loadContributionsFromSources(new Location(path), null, contributions);
 
         assertThat(contributions.size(), is(2)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source2.getName()));
         assertThat(contributions.get(1).getSourceName(), is(source3.getName()));
 
-        child1 = pathFactory.createSegment("bzA");
-        child2 = pathFactory.createSegment("bzB");
-        assertThat(contributions.get(0).isEmpty(), is(true));
-        assertThat(contributions.get(1).getChildren(), hasItems(child1));
+        hasChildren(contributions.get(0));
+        hasChildren(contributions.get(1), "bzA", "bzB");
     }
 
     @Test
@@ -399,40 +406,31 @@
 
         Path path = pathFactory.create("/a"); // from sources 1, 2 and 3
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(path, null, contributions);
+        executor.loadContributionsFromSources(new Location(path), null, contributions);
 
         assertThat(contributions.size(), is(3)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source1.getName()));
         assertThat(contributions.get(1).getSourceName(), is(source2.getName()));
         assertThat(contributions.get(2).getSourceName(), is(source3.getName()));
 
-        Path.Segment child1 = pathFactory.createSegment("nA");
-        Path.Segment child2 = pathFactory.createSegment("nB");
-        Path.Segment child3 = pathFactory.createSegment("nC");
-        Path.Segment child4 = pathFactory.createSegment("qA");
-        Path.Segment child5 = pathFactory.createSegment("qB");
-        Path.Segment child6 = pathFactory.createSegment("qC");
-        Path.Segment child7 = pathFactory.createSegment("ay");
-        assertThat(contributions.get(0).getChildren(), hasItems(child1, child2, child3));
-        assertThat(contributions.get(1).getChildren(), hasItems(child4, child5, child6));
-        assertThat(contributions.get(2).getChildren(), hasItems(child7));
+        hasChildren(contributions.get(0), "nA", "nB", "nC");
+        hasChildren(contributions.get(1), "qA", "qB", "qC");
+        hasChildren(contributions.get(2), "ay");
 
         path = pathFactory.create("/a/ay"); // from source 3
         contributions.clear();
-        executor.loadContributionsFromSources(path, null, contributions);
+        executor.loadContributionsFromSources(new Location(path), null, contributions);
 
         assertThat(contributions.size(), is(1)); // order is based upon order of projections
         assertThat(contributions.get(0).getSourceName(), is(source3.getName()));
-        child1 = pathFactory.createSegment("azA");
-        child2 = pathFactory.createSegment("azB");
-        assertThat(contributions.get(0).getChildren(), hasItems(child1, child2));
+        hasChildren(contributions.get(0), "azA", "azB");
     }
 
     @Test
     public void shouldFailToLoadNodeFromSourcesWhenTheNodeDoesNotAppearInAnyOfTheSources() throws Exception {
         Path nonExistant = pathFactory.create("/nonExistant/Node/In/AnySource");
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(nonExistant, null, contributions);
+        executor.loadContributionsFromSources(new Location(nonExistant), null, contributions);
         // All of the contributions should be empty ...
         for (Contribution contribution : contributions) {
             assertThat(contribution.isEmpty(), is(true));
@@ -472,7 +470,7 @@
 
         Path path = pathFactory.create("/a"); // from sources 1, 2 and 3
         List<Contribution> contributions = new LinkedList<Contribution>();
-        executor.loadContributionsFromSources(path, null, contributions);
+        executor.loadContributionsFromSources(new Location(path), null, contributions);
 
         // Check when the contributions expire ...
         DateTime nowInUtc = executor.getCurrentTimeInUtc();

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommandTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommandTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedCopyBranchCommandTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,108 +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.connector.federation.executor;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import org.jboss.dna.graph.commands.CopyBranchCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedCopyBranchCommandTest {
-    private ProjectedCopyBranchCommand command;
-    @Mock
-    private CopyBranchCommand wrapped;
-    @Mock
-    private Path projectedPath;
-    @Mock
-    private Path newProjectedPath;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        command = new ProjectedCopyBranchCommand(wrapped, projectedPath, newProjectedPath);
-    }
-
-    @Test
-    public void shouldReturnProjectedPath() {
-        assertThat(command.getPath(), is(sameInstance(projectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-    @Test
-    public void shouldReturnErrorFromWrappedCommands() {
-        Throwable error = mock(Throwable.class);
-        stub(wrapped.getError()).toReturn(error);
-        assertThat(command.getError(), is(error));
-        verify(wrapped).getError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForError() {
-        assertThat(command.hasError(), is(false));
-        verify(wrapped).hasError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForNoError() {
-        stub(wrapped.hasNoError()).toReturn(true);
-        assertThat(command.hasNoError(), is(true));
-        verify(wrapped).hasNoError();
-    }
-
-    @Test
-    public void shouldSetErrorOnWrappedCommand() {
-        Throwable error = mock(Throwable.class);
-        command.setError(error);
-        verify(wrapped).setError(error);
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForCancellation() {
-        stub(wrapped.isCancelled()).toReturn(true);
-        assertThat(command.isCancelled(), is(true));
-        verify(wrapped).isCancelled();
-    }
-
-    @Test
-    public void shouldReturnWrappedCommandAsOriginalCommand() {
-        assertThat(command.getOriginalCommand(), is(sameInstance(wrapped)));
-    }
-
-    @Test
-    public void shouldReturnNewProjectedPathForNewPath() {
-        assertThat(command.getNewPath(), is(sameInstance(newProjectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommandTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommandTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedCopyNodeCommandTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,108 +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.connector.federation.executor;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import org.jboss.dna.graph.commands.CopyNodeCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedCopyNodeCommandTest {
-    private ProjectedCopyNodeCommand command;
-    @Mock
-    private CopyNodeCommand wrapped;
-    @Mock
-    private Path projectedPath;
-    @Mock
-    private Path newProjectedPath;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        command = new ProjectedCopyNodeCommand(wrapped, projectedPath, newProjectedPath);
-    }
-
-    @Test
-    public void shouldReturnProjectedPath() {
-        assertThat(command.getPath(), is(sameInstance(projectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-    @Test
-    public void shouldReturnErrorFromWrappedCommands() {
-        Throwable error = mock(Throwable.class);
-        stub(wrapped.getError()).toReturn(error);
-        assertThat(command.getError(), is(error));
-        verify(wrapped).getError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForError() {
-        assertThat(command.hasError(), is(false));
-        verify(wrapped).hasError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForNoError() {
-        stub(wrapped.hasNoError()).toReturn(true);
-        assertThat(command.hasNoError(), is(true));
-        verify(wrapped).hasNoError();
-    }
-
-    @Test
-    public void shouldSetErrorOnWrappedCommand() {
-        Throwable error = mock(Throwable.class);
-        command.setError(error);
-        verify(wrapped).setError(error);
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForCancellation() {
-        stub(wrapped.isCancelled()).toReturn(true);
-        assertThat(command.isCancelled(), is(true));
-        verify(wrapped).isCancelled();
-    }
-
-    @Test
-    public void shouldReturnWrappedCommandAsOriginalCommand() {
-        assertThat(command.getOriginalCommand(), is(sameInstance(wrapped)));
-    }
-
-    @Test
-    public void shouldReturnNewProjectedPathForNewPath() {
-        assertThat(command.getNewPath(), is(sameInstance(newProjectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommandTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommandTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedDeleteBranchCommandTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,100 +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.connector.federation.executor;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import org.jboss.dna.graph.commands.DeleteBranchCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedDeleteBranchCommandTest {
-    private ProjectedDeleteBranchCommand command;
-    @Mock
-    private DeleteBranchCommand wrapped;
-    @Mock
-    private Path projectedPath;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        command = new ProjectedDeleteBranchCommand(wrapped, projectedPath);
-    }
-
-    @Test
-    public void shouldReturnProjectedPath() {
-        assertThat(command.getPath(), is(sameInstance(projectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-    @Test
-    public void shouldReturnErrorFromWrappedCommands() {
-        Throwable error = mock(Throwable.class);
-        stub(wrapped.getError()).toReturn(error);
-        assertThat(command.getError(), is(error));
-        verify(wrapped).getError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForError() {
-        assertThat(command.hasError(), is(false));
-        verify(wrapped).hasError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForNoError() {
-        stub(wrapped.hasNoError()).toReturn(true);
-        assertThat(command.hasNoError(), is(true));
-        verify(wrapped).hasNoError();
-    }
-
-    @Test
-    public void shouldSetErrorOnWrappedCommand() {
-        Throwable error = mock(Throwable.class);
-        command.setError(error);
-        verify(wrapped).setError(error);
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForCancellation() {
-        stub(wrapped.isCancelled()).toReturn(true);
-        assertThat(command.isCancelled(), is(true));
-        verify(wrapped).isCancelled();
-    }
-
-    @Test
-    public void shouldReturnWrappedCommandAsOriginalCommand() {
-        assertThat(command.getOriginalCommand(), is(sameInstance(wrapped)));
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommandTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommandTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetChildrenCommandTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,123 +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.connector.federation.executor;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GetChildrenCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Property;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedGetChildrenCommandTest {
-    private ProjectedGetChildrenCommand command;
-    @Mock
-    private GetChildrenCommand wrapped;
-    @Mock
-    private Path projectedPath;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        command = new ProjectedGetChildrenCommand(wrapped, projectedPath);
-    }
-
-    @Test
-    public void shouldReturnProjectedPath() {
-        assertThat(command.getPath(), is(sameInstance(projectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-    @Test
-    public void shouldReturnErrorFromWrappedCommands() {
-        Throwable error = mock(Throwable.class);
-        stub(wrapped.getError()).toReturn(error);
-        assertThat(command.getError(), is(error));
-        verify(wrapped).getError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForError() {
-        assertThat(command.hasError(), is(false));
-        verify(wrapped).hasError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForNoError() {
-        stub(wrapped.hasNoError()).toReturn(true);
-        assertThat(command.hasNoError(), is(true));
-        verify(wrapped).hasNoError();
-    }
-
-    @Test
-    public void shouldSetErrorOnWrappedCommand() {
-        Throwable error = mock(Throwable.class);
-        command.setError(error);
-        verify(wrapped).setError(error);
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForCancellation() {
-        stub(wrapped.isCancelled()).toReturn(true);
-        assertThat(command.isCancelled(), is(true));
-        verify(wrapped).isCancelled();
-    }
-
-    @Test
-    public void shouldReturnWrappedCommandAsOriginalCommand() {
-        assertThat(command.getOriginalCommand(), is(sameInstance(wrapped)));
-    }
-
-    @Test
-    public void shouldSetCachePolicyOnOriginalCommand() {
-        CachePolicy value = mock(CachePolicy.class);
-        command.setCachePolicy(value);
-        verify(wrapped).setCachePolicy(value);
-    }
-
-    @Test
-    public void shouldSetNoChildrenOnOriginalCommand() {
-        command.setNoChildren();
-        verify(wrapped).setNoChildren();
-    }
-
-    @Test
-    public void shouldAddChildrenOnOriginalCommand() {
-        Path.Segment segment = mock(Path.Segment.class);
-        Property[] properties = new Property[] {};
-        command.addChild(segment, properties);
-        verify(wrapped).addChild(segment, properties);
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommandTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommandTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetNodeCommandTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,129 +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.connector.federation.executor;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GetNodeCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Property;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedGetNodeCommandTest {
-    private ProjectedGetNodeCommand command;
-    @Mock
-    private GetNodeCommand wrapped;
-    @Mock
-    private Path projectedPath;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        command = new ProjectedGetNodeCommand(wrapped, projectedPath);
-    }
-
-    @Test
-    public void shouldReturnProjectedPath() {
-        assertThat(command.getPath(), is(sameInstance(projectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-    @Test
-    public void shouldReturnErrorFromWrappedCommands() {
-        Throwable error = mock(Throwable.class);
-        stub(wrapped.getError()).toReturn(error);
-        assertThat(command.getError(), is(error));
-        verify(wrapped).getError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForError() {
-        assertThat(command.hasError(), is(false));
-        verify(wrapped).hasError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForNoError() {
-        stub(wrapped.hasNoError()).toReturn(true);
-        assertThat(command.hasNoError(), is(true));
-        verify(wrapped).hasNoError();
-    }
-
-    @Test
-    public void shouldSetErrorOnWrappedCommand() {
-        Throwable error = mock(Throwable.class);
-        command.setError(error);
-        verify(wrapped).setError(error);
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForCancellation() {
-        stub(wrapped.isCancelled()).toReturn(true);
-        assertThat(command.isCancelled(), is(true));
-        verify(wrapped).isCancelled();
-    }
-
-    @Test
-    public void shouldReturnWrappedCommandAsOriginalCommand() {
-        assertThat(command.getOriginalCommand(), is(sameInstance(wrapped)));
-    }
-
-    @Test
-    public void shouldSetCachePolicyOnOriginalCommand() {
-        CachePolicy value = mock(CachePolicy.class);
-        command.setCachePolicy(value);
-        verify(wrapped).setCachePolicy(value);
-    }
-
-    @Test
-    public void shouldSetPropertyOnOriginalCommand() {
-        Property property = mock(Property.class);
-        command.setProperty(property);
-        verify(wrapped).setProperty(property);
-    }
-
-    @Test
-    public void shouldSetNoChildrenOnOriginalCommand() {
-        command.setNoChildren();
-        verify(wrapped).setNoChildren();
-    }
-
-    @Test
-    public void shouldAddChildrenOnOriginalCommand() {
-        Path.Segment segment = mock(Path.Segment.class);
-        Property[] properties = new Property[] {};
-        command.addChild(segment, properties);
-        verify(wrapped).addChild(segment, properties);
-    }
-}

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommandTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommandTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedGetPropertiesCommandTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,115 +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.connector.federation.executor;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.GetPropertiesCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Property;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedGetPropertiesCommandTest {
-    private ProjectedGetPropertiesCommand command;
-    @Mock
-    private GetPropertiesCommand wrapped;
-    @Mock
-    private Path projectedPath;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        command = new ProjectedGetPropertiesCommand(wrapped, projectedPath);
-    }
-
-    @Test
-    public void shouldReturnProjectedPath() {
-        assertThat(command.getPath(), is(sameInstance(projectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-    @Test
-    public void shouldReturnErrorFromWrappedCommands() {
-        Throwable error = mock(Throwable.class);
-        stub(wrapped.getError()).toReturn(error);
-        assertThat(command.getError(), is(error));
-        verify(wrapped).getError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForError() {
-        assertThat(command.hasError(), is(false));
-        verify(wrapped).hasError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForNoError() {
-        stub(wrapped.hasNoError()).toReturn(true);
-        assertThat(command.hasNoError(), is(true));
-        verify(wrapped).hasNoError();
-    }
-
-    @Test
-    public void shouldSetErrorOnWrappedCommand() {
-        Throwable error = mock(Throwable.class);
-        command.setError(error);
-        verify(wrapped).setError(error);
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForCancellation() {
-        stub(wrapped.isCancelled()).toReturn(true);
-        assertThat(command.isCancelled(), is(true));
-        verify(wrapped).isCancelled();
-    }
-
-    @Test
-    public void shouldReturnWrappedCommandAsOriginalCommand() {
-        assertThat(command.getOriginalCommand(), is(sameInstance(wrapped)));
-    }
-
-    @Test
-    public void shouldSetCachePolicyOnOriginalCommand() {
-        CachePolicy value = mock(CachePolicy.class);
-        command.setCachePolicy(value);
-        verify(wrapped).setCachePolicy(value);
-    }
-
-    @Test
-    public void shouldSetPropertyOnOriginalCommand() {
-        Property property = mock(Property.class);
-        command.setProperty(property);
-        verify(wrapped).setProperty(property);
-    }
-}

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommandTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommandTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedMoveBranchCommandTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,108 +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.connector.federation.executor;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import org.jboss.dna.graph.commands.MoveBranchCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedMoveBranchCommandTest {
-    private ProjectedMoveBranchCommand command;
-    @Mock
-    private MoveBranchCommand wrapped;
-    @Mock
-    private Path projectedPath;
-    @Mock
-    private Path newProjectedPath;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        command = new ProjectedMoveBranchCommand(wrapped, projectedPath, newProjectedPath);
-    }
-
-    @Test
-    public void shouldReturnProjectedPath() {
-        assertThat(command.getPath(), is(sameInstance(projectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-    @Test
-    public void shouldReturnErrorFromWrappedCommands() {
-        Throwable error = mock(Throwable.class);
-        stub(wrapped.getError()).toReturn(error);
-        assertThat(command.getError(), is(error));
-        verify(wrapped).getError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForError() {
-        assertThat(command.hasError(), is(false));
-        verify(wrapped).hasError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForNoError() {
-        stub(wrapped.hasNoError()).toReturn(true);
-        assertThat(command.hasNoError(), is(true));
-        verify(wrapped).hasNoError();
-    }
-
-    @Test
-    public void shouldSetErrorOnWrappedCommand() {
-        Throwable error = mock(Throwable.class);
-        command.setError(error);
-        verify(wrapped).setError(error);
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForCancellation() {
-        stub(wrapped.isCancelled()).toReturn(true);
-        assertThat(command.isCancelled(), is(true));
-        verify(wrapped).isCancelled();
-    }
-
-    @Test
-    public void shouldReturnWrappedCommandAsOriginalCommand() {
-        assertThat(command.getOriginalCommand(), is(sameInstance(wrapped)));
-    }
-
-    @Test
-    public void shouldReturnNewProjectedPathForNewPath() {
-        assertThat(command.getNewPath(), is(sameInstance(newProjectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommandTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommandTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedRecordBranchCommandTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,100 +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.connector.federation.executor;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import org.jboss.dna.graph.commands.RecordBranchCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedRecordBranchCommandTest {
-    private ProjectedRecordBranchCommand command;
-    @Mock
-    private RecordBranchCommand wrapped;
-    @Mock
-    private Path projectedPath;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        command = new ProjectedRecordBranchCommand(wrapped, projectedPath);
-    }
-
-    @Test
-    public void shouldReturnProjectedPath() {
-        assertThat(command.getPath(), is(sameInstance(projectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-    @Test
-    public void shouldReturnErrorFromWrappedCommands() {
-        Throwable error = mock(Throwable.class);
-        stub(wrapped.getError()).toReturn(error);
-        assertThat(command.getError(), is(error));
-        verify(wrapped).getError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForError() {
-        assertThat(command.hasError(), is(false));
-        verify(wrapped).hasError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForNoError() {
-        stub(wrapped.hasNoError()).toReturn(true);
-        assertThat(command.hasNoError(), is(true));
-        verify(wrapped).hasNoError();
-    }
-
-    @Test
-    public void shouldSetErrorOnWrappedCommand() {
-        Throwable error = mock(Throwable.class);
-        command.setError(error);
-        verify(wrapped).setError(error);
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForCancellation() {
-        stub(wrapped.isCancelled()).toReturn(true);
-        assertThat(command.isCancelled(), is(true));
-        verify(wrapped).isCancelled();
-    }
-
-    @Test
-    public void shouldReturnWrappedCommandAsOriginalCommand() {
-        assertThat(command.getOriginalCommand(), is(sameInstance(wrapped)));
-    }
-
-}

Deleted: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommandTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommandTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/executor/ProjectedSetPropertiesCommandTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -1,110 +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.connector.federation.executor;
-
-import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import java.util.ArrayList;
-import java.util.Collection;
-import org.jboss.dna.graph.commands.SetPropertiesCommand;
-import org.jboss.dna.graph.properties.Path;
-import org.jboss.dna.graph.properties.Property;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class ProjectedSetPropertiesCommandTest {
-    private ProjectedSetPropertiesCommand command;
-    @Mock
-    private SetPropertiesCommand wrapped;
-    @Mock
-    private Path projectedPath;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        command = new ProjectedSetPropertiesCommand(wrapped, projectedPath);
-    }
-
-    @Test
-    public void shouldReturnProjectedPath() {
-        assertThat(command.getPath(), is(sameInstance(projectedPath)));
-        verifyZeroInteractions(wrapped);
-    }
-
-    @Test
-    public void shouldReturnErrorFromWrappedCommands() {
-        Throwable error = mock(Throwable.class);
-        stub(wrapped.getError()).toReturn(error);
-        assertThat(command.getError(), is(error));
-        verify(wrapped).getError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForError() {
-        assertThat(command.hasError(), is(false));
-        verify(wrapped).hasError();
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForNoError() {
-        stub(wrapped.hasNoError()).toReturn(true);
-        assertThat(command.hasNoError(), is(true));
-        verify(wrapped).hasNoError();
-    }
-
-    @Test
-    public void shouldSetErrorOnWrappedCommand() {
-        Throwable error = mock(Throwable.class);
-        command.setError(error);
-        verify(wrapped).setError(error);
-    }
-
-    @Test
-    public void shouldCheckWrappedCommandForCancellation() {
-        stub(wrapped.isCancelled()).toReturn(true);
-        assertThat(command.isCancelled(), is(true));
-        verify(wrapped).isCancelled();
-    }
-
-    @Test
-    public void shouldReturnWrappedCommandAsOriginalCommand() {
-        assertThat(command.getOriginalCommand(), is(sameInstance(wrapped)));
-    }
-
-    @Test
-    public void shouldReturnPropertyIteratorFromOriginalCommand() {
-        Collection<Property> properties = new ArrayList<Property>();
-        stub(wrapped.getProperties()).toReturn(properties);
-        assertThat(command.getProperties(), is(sameInstance(properties)));
-        verify(wrapped).getProperties();
-    }
-}

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/FederatedNodeTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -22,19 +22,16 @@
 package org.jboss.dna.connector.federation.merge;
 
 import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsNot.not;
 import static org.hamcrest.core.IsNull.nullValue;
 import static org.hamcrest.core.IsSame.sameInstance;
 import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.stub;
 import java.util.UUID;
-import org.jboss.dna.graph.commands.NodeConflictBehavior;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.Path;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
 
 /**
  * @author Randall Hauch
@@ -43,14 +40,14 @@
 
     private FederatedNode node;
     private UUID uuid;
-    @Mock
-    private Path path;
+    private Location location;
 
     @Before
     public void beforeEach() {
         MockitoAnnotations.initMocks(this);
         uuid = UUID.randomUUID();
-        node = new FederatedNode(path, uuid);
+        location = new Location(mock(Path.class));
+        node = new FederatedNode(location, uuid);
     }
 
     @Test
@@ -60,7 +57,8 @@
 
     @Test
     public void shouldHaveSamePathSuppliedToConstructor() {
-        assertThat(node.getPath(), is(sameInstance(path)));
+        assertThat(node.at(), is(sameInstance(location)));
+        assertThat(node.getActualLocationOfNode(), is(sameInstance(location)));
     }
 
     @Test
@@ -75,47 +73,37 @@
         assertThat(node.getMergePlan(), is(sameInstance(mergePlan)));
     }
 
-    @Test
-    public void shouldHaveDefaultConflictBehaviorUponConstruction() {
-        assertThat(node.getConflictBehavior(), is(FederatedNode.DEFAULT_CONFLICT_BEHAVIOR));
-    }
+    // @Test
+    // public void shouldHaveDefaultConflictBehaviorUponConstruction() {
+    // assertThat(node.getConflictBehavior(), is(FederatedNode.DEFAULT_CONFLICT_BEHAVIOR));
+    // }
+    //
+    // @Test
+    // public void shouldAllowSettingConflictBehavior() {
+    // NodeConflictBehavior behavior = NodeConflictBehavior.REPLACE;
+    // assertThat(node.getConflictBehavior(), is(not(behavior)));
+    // node.setConflictBehavior(behavior);
+    // assertThat(node.getConflictBehavior(), is(behavior));
+    // }
+    //
+    // @Test
+    // public void shouldAllowSettingConflictBehaviorToNull() {
+    // node.setConflictBehavior(null);
+    // assertThat(node.getConflictBehavior(), is(FederatedNode.DEFAULT_CONFLICT_BEHAVIOR));
+    //
+    // // Set to something that is not the default, then set to null
+    // NodeConflictBehavior behavior = NodeConflictBehavior.REPLACE;
+    // assertThat(node.getConflictBehavior(), is(not(behavior)));
+    // node.setConflictBehavior(behavior);
+    // assertThat(node.getConflictBehavior(), is(behavior));
+    // node.setConflictBehavior(null);
+    // assertThat(node.getConflictBehavior(), is(FederatedNode.DEFAULT_CONFLICT_BEHAVIOR));
+    // }
 
     @Test
-    public void shouldAllowSettingConflictBehavior() {
-        NodeConflictBehavior behavior = NodeConflictBehavior.REPLACE;
-        assertThat(node.getConflictBehavior(), is(not(behavior)));
-        node.setConflictBehavior(behavior);
-        assertThat(node.getConflictBehavior(), is(behavior));
+    public void shouldHaveHashCodeThatIsTheHashCodeOfTheLocation() {
+        node = new FederatedNode(location, uuid);
+        assertThat(node.hashCode(), is(location.hashCode()));
     }
 
-    @Test
-    public void shouldAllowSettingConflictBehaviorToNull() {
-        node.setConflictBehavior(null);
-        assertThat(node.getConflictBehavior(), is(FederatedNode.DEFAULT_CONFLICT_BEHAVIOR));
-
-        // Set to something that is not the default, then set to null
-        NodeConflictBehavior behavior = NodeConflictBehavior.REPLACE;
-        assertThat(node.getConflictBehavior(), is(not(behavior)));
-        node.setConflictBehavior(behavior);
-        assertThat(node.getConflictBehavior(), is(behavior));
-        node.setConflictBehavior(null);
-        assertThat(node.getConflictBehavior(), is(FederatedNode.DEFAULT_CONFLICT_BEHAVIOR));
-    }
-
-    @Test
-    public void shouldCompareFederatedNodesBasedUponPaths() {
-        Path path2 = mock(Path.class);
-        stub(path2.compareTo(path)).toReturn(1);
-        stub(path.compareTo(path2)).toReturn(-1);
-        FederatedNode node2 = new FederatedNode(path2, UUID.randomUUID());
-        assertThat(node.compareTo(node2), is(-1));
-        assertThat(node2.compareTo(node), is(1));
-    }
-
-    @Test
-    public void shouldHaveHashCodeThatIsTheHashCodeOfTheUuid() {
-        node = new FederatedNode(path, uuid);
-        assertThat(node.hashCode(), is(uuid.hashCode()));
-    }
-
 }

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/OneContributionMergeStrategyTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -25,7 +25,6 @@
 import static org.hamcrest.core.IsNot.not;
 import static org.hamcrest.core.IsSame.sameInstance;
 import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.stub;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -37,6 +36,7 @@
 import org.jboss.dna.connector.federation.merge.MergePlan;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.connectors.BasicExecutionContext;
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
@@ -56,25 +56,27 @@
     private ExecutionContext context;
     private FederatedNode node;
     private Map<Name, Property> properties;
-    private List<Path.Segment> children;
+    private List<Location> children;
+    private Path parentPath;
     @Mock
     private Contribution contribution;
 
     @Before
     public void beforeEach() throws Exception {
         MockitoAnnotations.initMocks(this);
-        Path path = mock(Path.class);
-        node = new FederatedNode(path, UUID.randomUUID());
         strategy = new OneContributionMergeStrategy();
         contributions = new LinkedList<Contribution>();
         contributions.add(contribution);
         context = new BasicExecutionContext();
         context.getNamespaceRegistry().register("dna", "http://www.jboss.org/dna/something");
         context.getNamespaceRegistry().register("jcr", "http://www.jcr.org");
+        parentPath = context.getValueFactories().getPathFactory().create("/a/b/c");
+        node = new FederatedNode(new Location(parentPath), UUID.randomUUID());
         stub(contribution.getSourceName()).toReturn("source name");
-        children = new LinkedList<Path.Segment>();
+        children = new LinkedList<Location>();
         for (int i = 0; i != 10; ++i) {
-            children.add(context.getValueFactories().getPathFactory().createSegment("a" + i));
+            Path childPath = context.getValueFactories().getPathFactory().create(parentPath, "a" + i);
+            children.add(new Location(childPath));
         }
         properties = new HashMap<Name, Property>();
         for (int i = 0; i != 10; ++i) {

Modified: trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-federation/src/test/java/org/jboss/dna/connector/federation/merge/strategy/SimpleMergeStrategyTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -26,7 +26,6 @@
 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.mock;
 import static org.mockito.Mockito.stub;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -41,6 +40,7 @@
 import org.jboss.dna.connector.federation.merge.FederatedNode;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.connectors.BasicExecutionContext;
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
@@ -61,24 +61,25 @@
     private List<Contribution> contributions;
     private ExecutionContext context;
     private FederatedNode node;
+    protected Path parentPath;
 
     @Before
     public void beforeEach() throws Exception {
         MockitoAnnotations.initMocks(this);
-        Path path = mock(Path.class);
-        node = new FederatedNode(path, UUID.randomUUID());
         strategy = new SimpleMergeStrategy();
         contributions = new LinkedList<Contribution>();
         context = new BasicExecutionContext();
         context.getNamespaceRegistry().register("dna", "http://www.jboss.org/dna/something");
         context.getNamespaceRegistry().register("jcr", "http://www.jcr.org");
+        parentPath = context.getValueFactories().getPathFactory().create("/a/b/c");
+        node = new FederatedNode(new Location(parentPath), UUID.randomUUID());
     }
 
     @Test
     public void shouldAddChildrenFromOneContribution() {
         addContribution("source1").addChildren("childA", "childB[1]", "childB[2]");
         strategy.merge(node, contributions, context);
-        assertThat(node.getChildren(), hasSegments("childA", "childB[1]", "childB[2]"));
+        assertThat(node.getChildren(), hasChildLocations("childA", "childB[1]", "childB[2]"));
     }
 
     @Test
@@ -95,7 +96,7 @@
         addContribution("source1").addChildren("childA", "childB[1]", "childB[2]");
         addContribution("source2").addChildren("childX", "childY[1]", "childY[2]");
         strategy.merge(node, contributions, context);
-        assertThat(node.getChildren(), hasSegments("childA", "childB[1]", "childB[2]", "childX", "childY[1]", "childY[2]"));
+        assertThat(node.getChildren(), hasChildLocations("childA", "childB[1]", "childB[2]", "childX", "childY[1]", "childY[2]"));
     }
 
     @Test
@@ -104,14 +105,14 @@
         addContribution("source2").addChildren("childX", "childB", "childY");
         addContribution("source3").addChildren("childX", "childB");
         strategy.merge(node, contributions, context);
-        assertThat(node.getChildren(), hasSegments("childA",
-                                                   "childB[1]",
-                                                   "childB[2]",
-                                                   "childX[1]",
-                                                   "childB[3]",
-                                                   "childY",
-                                                   "childX[2]",
-                                                   "childB[4]"));
+        assertThat(node.getChildren(), hasChildLocations("childA",
+                                                         "childB[1]",
+                                                         "childB[2]",
+                                                         "childX[1]",
+                                                         "childB[3]",
+                                                         "childY",
+                                                         "childX[2]",
+                                                         "childB[4]"));
     }
 
     @Test
@@ -193,24 +194,24 @@
         assertThat(contributions.size(), is(0));
         addContribution("source1").addChildren("childA", "childB[1]", "childB[2]").setProperty("p1", "p1 value");
         assertThat(contributions.size(), is(1));
-        assertThat(contributions.get(0).getChildren(), hasSegmentIterator("childA", "childB[1]", "childB[2]"));
+        assertThat(contributions.get(0).getChildren(), hasLocationIterator("childA", "childB[1]", "childB[2]"));
     }
 
-    protected Matcher<List<Path.Segment>> hasSegments( String... segment ) {
-        List<Path.Segment> segments = new ArrayList<Path.Segment>();
-        for (String seg : segment) {
-            segments.add(context.getValueFactories().getPathFactory().createSegment(seg));
+    protected Matcher<List<Location>> hasChildLocations( String... childNames ) {
+        List<Location> locations = new ArrayList<Location>();
+        for (String childName : childNames) {
+            locations.add(new Location(context.getValueFactories().getPathFactory().create(parentPath, childName)));
         }
-        return equalTo(segments);
+        return equalTo(locations);
     }
 
-    protected Matcher<Iterator<Path.Segment>> hasSegmentIterator( String... segment ) {
-        Path.Segment[] segments = new Path.Segment[segment.length];
+    protected Matcher<Iterator<Location>> hasLocationIterator( String... childNames ) {
+        Location[] locations = new Location[childNames.length];
         int index = 0;
-        for (String seg : segment) {
-            segments[index++] = context.getValueFactories().getPathFactory().createSegment(seg);
+        for (String childName : childNames) {
+            locations[index++] = new Location(context.getValueFactories().getPathFactory().create(parentPath, childName));
         }
-        return IsIteratorContaining.hasItems(segments);
+        return IsIteratorContaining.hasItems(locations);
     }
 
     protected Name name( String name ) {
@@ -232,16 +233,17 @@
         protected final Contribution mockContribution;
         protected final ExecutionContext context;
         protected final Map<Name, Property> properties = new HashMap<Name, Property>();
-        protected final List<Path.Segment> children = new ArrayList<Path.Segment>();
+        protected final List<Location> children = new ArrayList<Location>();
 
         protected ContributionBuilder( ExecutionContext context,
                                        String name,
                                        List<Contribution> contributions ) {
             this.context = context;
             this.mockContribution = Mockito.mock(Contribution.class);
+            stub(mockContribution.getLocationInSource()).toReturn(new Location(parentPath));
             stub(mockContribution.getSourceName()).toReturn(name);
-            stub(mockContribution.getChildren()).toAnswer(new Answer<Iterator<Path.Segment>>() {
-                public Iterator<Path.Segment> answer( InvocationOnMock invocation ) throws Throwable {
+            stub(mockContribution.getChildren()).toAnswer(new Answer<Iterator<Location>>() {
+                public Iterator<Location> answer( InvocationOnMock invocation ) throws Throwable {
                     return ContributionBuilder.this.children.iterator();
                 }
             });
@@ -266,27 +268,14 @@
             return this.mockContribution;
         }
 
-        public ContributionBuilder addChildren( String... segmentNamesForChildren ) {
-            for (String childSegmentName : segmentNamesForChildren) {
-                children.add(context.getValueFactories().getPathFactory().createSegment(childSegmentName));
+        public ContributionBuilder addChildren( String... pathsForChildren ) {
+            for (String childPath : pathsForChildren) {
+                Path path = context.getValueFactories().getPathFactory().create(parentPath, childPath);
+                children.add(new Location(path));
             }
             return this;
         }
 
-        public ContributionBuilder addChildren( Name... segmentNamesForChildren ) {
-            for (Name childSegmentName : segmentNamesForChildren) {
-                children.add(context.getValueFactories().getPathFactory().createSegment(childSegmentName));
-            }
-            return this;
-        }
-
-        public ContributionBuilder addChildren( Path.Segment... segmentNamesForChildren ) {
-            for (Path.Segment childSegmentName : segmentNamesForChildren) {
-                children.add(childSegmentName);
-            }
-            return this;
-        }
-
         public ContributionBuilder setProperty( String name,
                                                 Object... values ) {
             Name propertyName = context.getValueFactories().getNameFactory().create(name);

Modified: trunk/extensions/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java
===================================================================
--- trunk/extensions/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepository.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -29,28 +29,28 @@
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.CommonI18n;
 import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.commands.ActsOnPath;
-import org.jboss.dna.graph.commands.CopyBranchCommand;
-import org.jboss.dna.graph.commands.CopyNodeCommand;
-import org.jboss.dna.graph.commands.CreateNodeCommand;
-import org.jboss.dna.graph.commands.DeleteBranchCommand;
-import org.jboss.dna.graph.commands.GetChildrenCommand;
-import org.jboss.dna.graph.commands.GetPropertiesCommand;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.commands.MoveBranchCommand;
-import org.jboss.dna.graph.commands.RecordBranchCommand;
-import org.jboss.dna.graph.commands.SetPropertiesCommand;
-import org.jboss.dna.graph.commands.executor.AbstractCommandExecutor;
-import org.jboss.dna.graph.commands.executor.CommandExecutor;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.Path;
+import org.jboss.dna.graph.properties.PathFactory;
 import org.jboss.dna.graph.properties.PathNotFoundException;
 import org.jboss.dna.graph.properties.Property;
+import org.jboss.dna.graph.properties.PropertyFactory;
 import org.jboss.dna.graph.properties.Path.Segment;
 import org.jboss.dna.graph.properties.basic.BasicPath;
+import org.jboss.dna.graph.requests.CopyBranchRequest;
+import org.jboss.dna.graph.requests.CreateNodeRequest;
+import org.jboss.dna.graph.requests.DeleteBranchRequest;
+import org.jboss.dna.graph.requests.MoveBranchRequest;
+import org.jboss.dna.graph.requests.ReadAllChildrenRequest;
+import org.jboss.dna.graph.requests.ReadAllPropertiesRequest;
+import org.jboss.dna.graph.requests.Request;
+import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
+import org.jboss.dna.graph.requests.processor.RequestProcessor;
 
 /**
  * @author Randall Hauch
@@ -293,10 +293,10 @@
         correctSameNameSiblingIndexes(context, newParent, node.getName().getName());
     }
 
-    public int copyNode( ExecutionContext context,
-                         Node original,
-                         Node newParent,
-                         boolean recursive ) {
+    public Node copyNode( ExecutionContext context,
+                          Node original,
+                          Node newParent,
+                          boolean recursive ) {
         assert context != null;
         assert original != null;
         assert newParent != null;
@@ -306,45 +306,84 @@
         // 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(context, child, copy, true);
+                copyNode(context, child, copy, true);
             }
         }
-        return numNodesCopied;
+        return copy;
     }
 
     /**
-     * Get a command executor given the supplied environment and source name.
+     * Get a request processor given the supplied environment and source name.
      * 
      * @param context the environment in which the commands are to be executed
      * @param sourceName the name of the repository source
-     * @return the executor; never null
+     * @return the request processor; never null
      */
-    public CommandExecutor getCommandExecutor( ExecutionContext context,
-                                               String sourceName ) {
-        return new Executor(context, sourceName);
+    /*package*/RequestProcessor getRequestProcessor( ExecutionContext context,
+                                                      String sourceName ) {
+        return new Processor(context, sourceName);
     }
 
-    protected class Executor extends AbstractCommandExecutor {
+    protected class Processor extends RequestProcessor {
+        private final PathFactory pathFactory;
+        private final PropertyFactory propertyFactory;
 
-        private final Name uuidPropertyName;
+        protected Processor( ExecutionContext context,
+                             String sourceName ) {
+            super(sourceName, context);
+            pathFactory = context.getValueFactories().getPathFactory();
+            propertyFactory = context.getPropertyFactory();
+        }
 
-        protected Executor( ExecutionContext context,
-                            String sourceName ) {
-            super(context, sourceName);
-            this.uuidPropertyName = context.getValueFactories().getNameFactory().create(DnaLexicon.UUID);
+        @Override
+        public void process( ReadAllChildrenRequest request ) {
+            Node node = getTargetNode(request, request.of());
+            if (node == null) return;
+            Path path = request.of().getPath();
+            // Get the names of the children ...
+            List<Node> children = node.getChildren();
+            for (Node child : children) {
+                Segment childName = child.getName();
+                Path childPath = pathFactory.create(path, childName);
+                request.addChild(childPath, propertyFactory.create(DnaLexicon.UUID, child.getUuid()));
+            }
+            request.setActualLocationOfNode(new Location(path, node.getUuid()));
         }
 
-        protected Property getUuidProperty( Node node ) {
-            return getExecutionContext().getPropertyFactory().create(uuidPropertyName, node.getUuid());
+        @Override
+        public void process( ReadAllPropertiesRequest request ) {
+            Node node = getTargetNode(request, request.at());
+            if (node == null) return;
+            // Get the properties of the node ...
+            request.addProperty(propertyFactory.create(DnaLexicon.UUID, node.getUuid()));
+            for (Property property : node.getProperties().values()) {
+                request.addProperty(property);
+            }
+            request.setActualLocationOfNode(new Location(request.at().getPath(), node.getUuid()));
         }
 
         @Override
-        public void execute( CreateNodeCommand command ) {
-            Path path = command.getPath();
+        public void process( CopyBranchRequest request ) {
+            Node node = getTargetNode(request, request.from());
+            if (node == null) return;
+            // Look up the new parent, which must exist ...
+            Path newPath = request.into().getPath();
+            Path newParentPath = newPath.getParent();
+            Node newParent = getNode(newParentPath);
+            Node newNode = copyNode(getExecutionContext(), node, newParent, true);
+            newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, newNode.getName());
+            Location oldLocation = new Location(request.from().getPath(), node.getUuid());
+            Location newLocation = new Location(newPath, newNode.getUuid());
+            request.setActualLocations(oldLocation, newLocation);
+        }
+
+        @Override
+        public void process( CreateNodeRequest request ) {
+            Path path = request.at().getPath();
+            CheckArg.isNotNull(path, "request.at().getPath()");
             Node node = null;
             if (!path.isRoot()) {
                 Path parent = path.getParent();
@@ -352,137 +391,93 @@
                 Node parentNode = getNode(parent);
                 if (parentNode == null) {
                     Path lowestExisting = getLowestExistingPath(parent);
-                    throw new PathNotFoundException(path, lowestExisting, InMemoryConnectorI18n.nodeDoesNotExist.text(parent));
+                    throw new PathNotFoundException(request.at(), lowestExisting,
+                                                    InMemoryConnectorI18n.nodeDoesNotExist.text(parent));
                 }
                 UUID uuid = null;
-                for (Property property : command.getProperties()) {
-                    if (property.getName().equals(uuidPropertyName)) {
+                for (Property property : request.properties()) {
+                    if (property.getName().equals(DnaLexicon.UUID)) {
                         uuid = getExecutionContext().getValueFactories().getUuidFactory().create(property.getValues().next());
                         break;
                     }
                 }
                 node = createNode(getExecutionContext(), parentNode, path.getLastSegment().getName(), uuid);
+                path = getExecutionContext().getValueFactories().getPathFactory().create(parent, node.getName());
             } else {
                 node = getRoot();
             }
             // Now add the properties to the supplied node ...
-            for (Property property : command.getProperties()) {
+            for (Property property : request.properties()) {
                 Name propName = property.getName();
                 if (property.size() == 0) {
                     node.getProperties().remove(propName);
                     continue;
                 }
-                if (!propName.equals(uuidPropertyName)) {
+                if (!propName.equals(DnaLexicon.UUID)) {
                     node.getProperties().put(propName, property);
                 }
             }
             assert node != null;
+            request.setActualLocationOfNode(new Location(path, node.getUuid()));
         }
 
         @Override
-        public void execute( GetChildrenCommand command ) {
-            Node node = getTargetNode(command);
+        public void process( DeleteBranchRequest request ) {
+            Node node = getTargetNode(request, request.at());
             if (node == null) return;
-            // Get the names of the children ...
-            List<Node> children = node.getChildren();
-            for (Node child : children) {
-                Segment childName = child.getName();
-                command.addChild(childName, getUuidProperty(child));
-            }
+            removeNode(getExecutionContext(), node);
+            request.setActualLocationOfNode(new Location(request.at().getPath(), node.getUuid()));
         }
 
         @Override
-        public void execute( GetPropertiesCommand command ) {
-            Node node = getTargetNode(command);
+        public void process( MoveBranchRequest request ) {
+            Node node = getTargetNode(request, request.from());
             if (node == null) return;
-            for (Property property : node.getProperties().values()) {
-                command.setProperty(property);
-            }
-            command.setProperty(getUuidProperty(node));
+            // Look up the new parent, which must exist ...
+            Path newPath = request.into().getPath();
+            Path newParentPath = newPath.getParent();
+            Node newParent = getNode(newParentPath);
+            node.setParent(newParent);
+            newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName());
+            Location oldLocation = new Location(request.from().getPath(), node.getUuid());
+            Location newLocation = new Location(newPath, node.getUuid());
+            request.setActualLocations(oldLocation, newLocation);
         }
 
         @Override
-        public void execute( SetPropertiesCommand command ) {
-            Node node = getTargetNode(command);
+        public void process( UpdatePropertiesRequest request ) {
+            Node node = getTargetNode(request, request.on());
             if (node == null) return;
             // Now set (or remove) the properties to the supplied node ...
-            for (Property property : command.getProperties()) {
+            for (Property property : request.properties()) {
                 Name propName = property.getName();
                 if (property.size() == 0) {
                     node.getProperties().remove(propName);
                     continue;
                 }
-                if (!propName.equals(uuidPropertyName)) {
+                if (!propName.equals(DnaLexicon.UUID)) {
                     node.getProperties().put(propName, property);
                 }
             }
+            request.setActualLocationOfNode(new Location(request.on().getPath(), node.getUuid()));
         }
 
-        @Override
-        public void execute( DeleteBranchCommand command ) {
-            Node node = getTargetNode(command);
-            if (node == null) return;
-            removeNode(getExecutionContext(), node);
-        }
-
-        @Override
-        public void execute( CopyNodeCommand command ) {
-            Node node = getTargetNode(command);
-            if (node == null) return;
-            // Look up the new parent, which must exist ...
-            Path newPath = command.getNewPath();
-            Node newParent = getNode(newPath.getParent());
-            copyNode(getExecutionContext(), node, newParent, false);
-        }
-
-        @Override
-        public void execute( CopyBranchCommand command ) {
-            Node node = getTargetNode(command);
-            if (node == null) return;
-            // Look up the new parent, which must exist ...
-            Path newPath = command.getNewPath();
-            Node newParent = getNode(newPath.getParent());
-            copyNode(getExecutionContext(), node, newParent, true);
-        }
-
-        @Override
-        public void execute( MoveBranchCommand command ) {
-            Node node = getTargetNode(command);
-            if (node == null) return;
-            // Look up the new parent, which must exist ...
-            Path newPath = command.getNewPath();
-            Node newParent = getNode(newPath.getParent());
-            node.setParent(newParent);
-        }
-
-        @Override
-        public void execute( RecordBranchCommand command ) {
-            Node node = getTargetNode(command);
-            if (node == null) return;
-            recordNode(command, node);
-        }
-
-        protected void recordNode( RecordBranchCommand command,
-                                   Node node ) {
-            command.record(command.getPath(), node.getProperties().values());
-            for (Node child : node.getChildren()) {
-                recordNode(command, child);
+        protected Node getTargetNode( Request request,
+                                      Location location ) {
+            Path path = location.getPath();
+            if (path == null) {
+                request.setError(new IllegalArgumentException(CommonI18n.argumentMayNotBeNull.text("location.getPath()")));
+                return null;
             }
-        }
-
-        protected <T extends ActsOnPath & GraphCommand> Node getTargetNode( T command ) {
-            Path path = command.getPath();
             // Look up the node with the supplied path ...
             Node node = InMemoryRepository.this.getNode(path);
             if (node == null) {
                 Path lowestExisting = getLowestExistingPath(path);
-                command.setError(new PathNotFoundException(path, lowestExisting,
+                request.setError(new PathNotFoundException(location, lowestExisting,
                                                            InMemoryConnectorI18n.nodeDoesNotExist.text(path)));
                 return null;
             }
             return node;
         }
-
     }
-
 }

Modified: trunk/extensions/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java
===================================================================
--- trunk/extensions/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-inmemory/src/main/java/org/jboss/dna/connector/inmemory/InMemoryRepositoryConnection.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -28,13 +28,11 @@
 import org.jboss.dna.common.util.Logger;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.ActsAsUpdate;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.commands.executor.CommandExecutor;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositorySourceException;
 import org.jboss.dna.graph.connectors.RepositorySourceListener;
 import org.jboss.dna.graph.requests.Request;
+import org.jboss.dna.graph.requests.processor.RequestProcessor;
 
 /**
  * @author Randall Hauch
@@ -111,10 +109,11 @@
     /**
      * {@inheritDoc}
      * 
-     * @throws RepositorySourceException
+     * @see org.jboss.dna.graph.connectors.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
+     *      org.jboss.dna.graph.requests.Request)
      */
     public void execute( ExecutionContext context,
-                         GraphCommand... commands ) throws RepositorySourceException {
+                         Request request ) throws RepositorySourceException {
         Logger logger = context.getLogger(getClass());
         Stopwatch sw = null;
         if (logger.isTraceEnabled()) {
@@ -122,24 +121,16 @@
             sw.start();
         }
         // 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;
-            }
-        }
+        RequestProcessor processor = this.content.getRequestProcessor(context, this.getSourceName());
 
-        CommandExecutor executor = this.content.getCommandExecutor(context, this.getSourceName());
+        Lock lock = request.isReadOnly() ? content.getLock().readLock() : content.getLock().writeLock();
+        lock.lock();
         try {
             // Obtain the lock and execute the commands ...
-            lock.lock();
-            for (GraphCommand command : commands) {
-                executor.execute(command);
-            }
+            processor.process(request);
         } finally {
             try {
-                executor.close();
+                processor.close();
             } finally {
                 lock.unlock();
             }
@@ -151,18 +142,6 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.connectors.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
-     *      org.jboss.dna.graph.requests.Request)
-     */
-    public void execute( ExecutionContext context,
-                         Request request ) throws RepositorySourceException {
-        // TODO
-        throw new UnsupportedOperationException();
-    }
-
     protected InMemoryRepository getContent() {
         return content;
     }

Modified: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -29,30 +29,20 @@
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 import javax.transaction.xa.XAResource;
 import org.jboss.cache.Cache;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.Node;
 import org.jboss.dna.common.util.StringUtil;
+import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.CopyBranchCommand;
-import org.jboss.dna.graph.commands.CopyNodeCommand;
-import org.jboss.dna.graph.commands.CreateNodeCommand;
-import org.jboss.dna.graph.commands.DeleteBranchCommand;
-import org.jboss.dna.graph.commands.GetChildrenCommand;
-import org.jboss.dna.graph.commands.GetPropertiesCommand;
-import org.jboss.dna.graph.commands.GraphCommand;
-import org.jboss.dna.graph.commands.MoveBranchCommand;
-import org.jboss.dna.graph.commands.RecordBranchCommand;
-import org.jboss.dna.graph.commands.SetPropertiesCommand;
-import org.jboss.dna.graph.commands.executor.AbstractCommandExecutor;
-import org.jboss.dna.graph.commands.executor.CommandExecutor;
 import org.jboss.dna.graph.connectors.RepositoryConnection;
 import org.jboss.dna.graph.connectors.RepositorySourceException;
 import org.jboss.dna.graph.connectors.RepositorySourceListener;
 import org.jboss.dna.graph.properties.Name;
-import org.jboss.dna.graph.properties.NameFactory;
 import org.jboss.dna.graph.properties.Path;
 import org.jboss.dna.graph.properties.PathFactory;
 import org.jboss.dna.graph.properties.PathNotFoundException;
@@ -60,7 +50,15 @@
 import org.jboss.dna.graph.properties.PropertyFactory;
 import org.jboss.dna.graph.properties.ValueFactory;
 import org.jboss.dna.graph.properties.Path.Segment;
+import org.jboss.dna.graph.requests.CopyBranchRequest;
+import org.jboss.dna.graph.requests.CreateNodeRequest;
+import org.jboss.dna.graph.requests.DeleteBranchRequest;
+import org.jboss.dna.graph.requests.MoveBranchRequest;
+import org.jboss.dna.graph.requests.ReadAllChildrenRequest;
+import org.jboss.dna.graph.requests.ReadAllPropertiesRequest;
 import org.jboss.dna.graph.requests.Request;
+import org.jboss.dna.graph.requests.UpdatePropertiesRequest;
+import org.jboss.dna.graph.requests.processor.RequestProcessor;
 
 /**
  * The repository connection to a JBoss Cache instance.
@@ -80,7 +78,6 @@
         }
     };
 
-    private Name uuidPropertyName;
     private final JBossCacheSource source;
     private final Cache<Name, Object> cache;
     private RepositorySourceListener listener = NO_OP_LISTENER;
@@ -146,26 +143,161 @@
 
     /**
      * {@inheritDoc}
-     */
-    public void execute( ExecutionContext context,
-                         GraphCommand... commands ) throws RepositorySourceException {
-        // Now execute the commands ...
-        CommandExecutor executor = new Executor(context, this.getSourceName());
-        for (GraphCommand command : commands) {
-            executor.execute(command);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
      * 
      * @see org.jboss.dna.graph.connectors.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
      *      org.jboss.dna.graph.requests.Request)
      */
-    public void execute( ExecutionContext context,
-                         Request request ) throws RepositorySourceException {
-        // TODO
-        throw new UnsupportedOperationException();
+    public void execute( final ExecutionContext context,
+                         final Request request ) throws RepositorySourceException {
+        final PathFactory pathFactory = context.getValueFactories().getPathFactory();
+        final PropertyFactory propertyFactory = context.getPropertyFactory();
+        final ValueFactory<UUID> uuidFactory = context.getValueFactories().getUuidFactory();
+        RequestProcessor processor = new RequestProcessor(getSourceName(), context) {
+            @Override
+            public void process( ReadAllChildrenRequest request ) {
+                Path nodePath = request.of().getPath();
+                Node<Name, Object> node = getNode(context, nodePath);
+                // Get the names of the children, using the child list ...
+                Path.Segment[] childList = (Path.Segment[])node.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
+                for (Path.Segment child : childList) {
+                    // We have the child segment, but we need the UUID property ...
+                    Node<Name, Object> childNode = node.getChild(child);
+                    Object uuid = childNode.get(DnaLexicon.UUID);
+                    if (uuid == null) {
+                        uuid = generateUuid();
+                        childNode.put(DnaLexicon.UUID, uuid);
+                    } else {
+                        uuid = uuidFactory.create(uuid);
+                    }
+                    Property uuidProperty = propertyFactory.create(DnaLexicon.UUID, uuid);
+                    request.addChild(pathFactory.create(nodePath, child), uuidProperty);
+                }
+                UUID uuid = uuidFactory.create(node.get(DnaLexicon.UUID));
+                request.setActualLocationOfNode(new Location(nodePath, uuid));
+            }
+
+            @Override
+            public void process( ReadAllPropertiesRequest request ) {
+                Path nodePath = request.at().getPath();
+                Node<Name, Object> node = getNode(context, nodePath);
+                Map<Name, Object> dataMap = node.getData();
+                for (Map.Entry<Name, Object> data : dataMap.entrySet()) {
+                    Name propertyName = data.getKey();
+                    // Don't allow the child list property to be accessed
+                    if (propertyName.equals(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST)) continue;
+                    Object values = data.getValue();
+                    Property property = propertyFactory.create(propertyName, values);
+                    request.addProperty(property);
+                }
+                UUID uuid = uuidFactory.create(node.get(DnaLexicon.UUID));
+                request.setActualLocationOfNode(new Location(nodePath, uuid));
+            }
+
+            @Override
+            public void process( CreateNodeRequest request ) {
+                Path path = request.at().getPath();
+                Path parent = path.getParent();
+                // Look up the parent node, which must exist ...
+                Node<Name, Object> parentNode = getNode(context, parent);
+
+                // Update the children to account for same-name siblings.
+                // This not only updates the FQN of the child nodes, but it also sets the property that stores the
+                // the array of Path.Segment for the children (since the cache doesn't maintain order).
+                Path.Segment newSegment = updateChildList(parentNode,
+                                                          path.getLastSegment().getName(),
+                                                          getExecutionContext(),
+                                                          true);
+                Node<Name, Object> node = parentNode.addChild(Fqn.fromElements(newSegment));
+                assert checkChildren(parentNode);
+
+                // Add the UUID property (if required), which may be overwritten by a supplied property ...
+                node.put(DnaLexicon.UUID, generateUuid());
+                // Now add the properties to the supplied node ...
+                for (Property property : request.properties()) {
+                    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);
+                }
+                UUID uuid = uuidFactory.create(node.get(DnaLexicon.UUID));
+                Path nodePath = pathFactory.create(parent, newSegment);
+                request.setActualLocationOfNode(new Location(nodePath, uuid));
+            }
+
+            @Override
+            public void process( UpdatePropertiesRequest request ) {
+                Path nodePath = request.on().getPath();
+                Node<Name, Object> node = getNode(context, nodePath);
+                // Now set (or remove) the properties to the supplied node ...
+                for (Property property : request.properties()) {
+                    Name propName = property.getName();
+                    // Don't allow the child list property to be removed or changed
+                    if (propName.equals(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST)) continue;
+                    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);
+                }
+                UUID uuid = uuidFactory.create(node.get(DnaLexicon.UUID));
+                request.setActualLocationOfNode(new Location(nodePath, uuid));
+            }
+
+            @Override
+            public void process( CopyBranchRequest request ) {
+                Path nodePath = request.from().getPath();
+                Node<Name, Object> node = getNode(context, nodePath);
+                // Look up the new parent, which must exist ...
+                Path newParentPath = request.into().getPath();
+                Node<Name, Object> newParent = getNode(context, newParentPath);
+                Path.Segment newSegment = copyNode(node, newParent, true, null, null, getExecutionContext());
+
+                UUID uuid = uuidFactory.create(node.get(DnaLexicon.UUID));
+                Path newPath = pathFactory.create(newParentPath, newSegment);
+                request.setActualLocations(new Location(nodePath, uuid), new Location(newPath, uuid));
+            }
+
+            @Override
+            public void process( DeleteBranchRequest request ) {
+                Path nodePath = request.at().getPath();
+                Node<Name, Object> node = getNode(context, nodePath);
+                node.getParent().removeChild(node.getFqn().getLastElement());
+                UUID uuid = uuidFactory.create(node.get(DnaLexicon.UUID));
+                request.setActualLocationOfNode(new Location(nodePath, uuid));
+            }
+
+            @Override
+            public void process( MoveBranchRequest request ) {
+                Path nodePath = request.from().getPath();
+                Node<Name, Object> node = getNode(context, nodePath);
+                boolean recursive = true;
+                // Look up the new parent, which must exist ...
+                Path newParentPath = request.into().getPath();
+                Node<Name, Object> newParent = getNode(context, newParentPath);
+                Path.Segment newSegment = copyNode(node, newParent, recursive, DnaLexicon.UUID, null, getExecutionContext());
+
+                // Now delete the old node ...
+                Node<Name, Object> oldParent = node.getParent();
+                boolean removed = oldParent.removeChild(node.getFqn().getLastElement());
+                assert removed;
+
+                UUID uuid = uuidFactory.create(node.get(DnaLexicon.UUID));
+                Path newPath = pathFactory.create(newParentPath, newSegment);
+                request.setActualLocations(new Location(nodePath, uuid), new Location(newPath, uuid));
+            }
+        };
+        processor.process(request);
     }
 
     /**
@@ -175,22 +307,6 @@
         return this.listener;
     }
 
-    /**
-     * Utility method to calculate (if required) and obtain the name that should be used to store the UUID values for each node.
-     * This method may be called without regard to synchronization, since it should return the same value if it happens to be
-     * called concurrently while not yet initialized.
-     * 
-     * @param context the execution context
-     * @return the name, or null if the UUID should not be stored
-     */
-    protected Name getUuidPropertyName( ExecutionContext context ) {
-        if (uuidPropertyName == null) {
-            NameFactory nameFactory = context.getValueFactories().getNameFactory();
-            uuidPropertyName = nameFactory.create(this.source.getUuidPropertyName());
-        }
-        return this.uuidPropertyName;
-    }
-
     protected Fqn<?> getFullyQualifiedName( Path path ) {
         assert path != null;
         return Fqn.fromList(path.getSegmentsList());
@@ -230,7 +346,8 @@
                     fqn = null;
                 }
             }
-            throw new PathNotFoundException(path, lowestExisting, JBossCacheConnectorI18n.nodeDoesNotExist.text(nodePath));
+            throw new PathNotFoundException(new Location(path), lowestExisting,
+                                            JBossCacheConnectorI18n.nodeDoesNotExist.text(nodePath));
         }
         return node;
 
@@ -240,11 +357,12 @@
         return UUID.randomUUID();
     }
 
-    protected int copyNode( Node<Name, Object> original,
-                            Node<Name, Object> newParent,
-                            boolean recursive,
-                            Name uuidProperty,
-                            ExecutionContext context ) {
+    protected Path.Segment copyNode( Node<Name, Object> original,
+                                     Node<Name, Object> newParent,
+                                     boolean recursive,
+                                     Name uuidProperty,
+                                     AtomicInteger count,
+                                     ExecutionContext context ) {
         assert original != null;
         assert newParent != null;
         // Get or create the new node ...
@@ -263,14 +381,14 @@
             // Generate a new UUID for the new node, overwriting any existing value from the original ...
             copy.put(uuidProperty, generateUuid());
         }
-        int numNodesCopied = 1;
+        if (count != null) count.incrementAndGet();
         if (recursive) {
             // Loop over each child and call this method ...
             for (Node<Name, Object> child : original.getChildren()) {
-                numNodesCopied += copyNode(child, copy, true, uuidProperty, context);
+                copyNode(child, copy, true, uuidProperty, count, context);
             }
         }
-        return numNodesCopied;
+        return newSegment;
     }
 
     /**
@@ -457,177 +575,4 @@
         // Remove the existing ...
         parent.removeChild(existing);
     }
-
-    protected class Executor extends AbstractCommandExecutor {
-
-        private final PropertyFactory propertyFactory;
-        private final ValueFactory<UUID> uuidFactory;
-
-        protected Executor( ExecutionContext context,
-                            String sourceName ) {
-            super(context, sourceName);
-            this.propertyFactory = context.getPropertyFactory();
-            this.uuidFactory = context.getValueFactories().getUuidFactory();
-        }
-
-        @Override
-        public void execute( CreateNodeCommand command ) {
-            Path path = command.getPath();
-            Path parent = path.getParent();
-            // Look up the parent node, which must exist ...
-            Node<Name, Object> parentNode = getNode(parent);
-
-            // Update the children to account for same-name siblings.
-            // This not only updates the FQN of the child nodes, but it also sets the property that stores the
-            // the array of Path.Segment for the children (since the cache doesn't maintain order).
-            Path.Segment newSegment = updateChildList(parentNode, path.getLastSegment().getName(), getExecutionContext(), true);
-            Node<Name, Object> node = parentNode.addChild(Fqn.fromElements(newSegment));
-            assert checkChildren(parentNode);
-
-            // Add the UUID property (if required), which may be overwritten by a supplied property ...
-            Name uuidPropertyName = getUuidPropertyName(getExecutionContext());
-            if (uuidPropertyName != null) {
-                node.put(uuidPropertyName, generateUuid());
-            }
-            // Now add the properties to the supplied node ...
-            for (Property property : command.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);
-            }
-        }
-
-        @Override
-        public void execute( GetChildrenCommand command ) {
-            Node<Name, Object> node = getNode(command.getPath());
-            Name uuidPropertyName = getUuidPropertyName(getExecutionContext());
-            // Get the names of the children, using the child list ...
-            Path.Segment[] childList = (Path.Segment[])node.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
-            for (Path.Segment child : childList) {
-                // We have the child segment, but we need the UUID property ...
-                Node<Name, Object> childNode = node.getChild(child);
-                Object uuid = childNode.get(uuidPropertyName);
-                if (uuid == null) {
-                    uuid = generateUuid();
-                    childNode.put(uuidPropertyName, uuid);
-                } else {
-                    uuid = uuidFactory.create(uuid);
-                }
-                Property uuidProperty = propertyFactory.create(uuidPropertyName, uuid);
-                command.addChild(child, uuidProperty);
-            }
-        }
-
-        @Override
-        public void execute( GetPropertiesCommand command ) {
-            Node<Name, Object> node = getNode(command.getPath());
-            Map<Name, Object> dataMap = node.getData();
-            for (Map.Entry<Name, Object> data : dataMap.entrySet()) {
-                Name propertyName = data.getKey();
-                // Don't allow the child list property to be accessed
-                if (propertyName.equals(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST)) continue;
-                Object values = data.getValue();
-                Property property = propertyFactory.create(propertyName, values);
-                command.setProperty(property);
-            }
-        }
-
-        @Override
-        public void execute( SetPropertiesCommand command ) {
-            Node<Name, Object> node = getNode(command.getPath());
-            // Now set (or remove) the properties to the supplied node ...
-            for (Property property : command.getProperties()) {
-                Name propName = property.getName();
-                // Don't allow the child list property to be removed or changed
-                if (propName.equals(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST)) continue;
-                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);
-            }
-        }
-
-        @Override
-        public void execute( DeleteBranchCommand command ) {
-            Node<Name, Object> node = getNode(command.getPath());
-            node.getParent().removeChild(node.getFqn().getLastElement());
-        }
-
-        @Override
-        public void execute( CopyNodeCommand command ) {
-            Node<Name, Object> node = getNode(command.getPath());
-            // Look up the new parent, which must exist ...
-            Path newPath = command.getNewPath();
-            Node<Name, Object> newParent = getNode(newPath.getParent());
-            copyNode(node, newParent, false, null, getExecutionContext());
-        }
-
-        @Override
-        public void execute( CopyBranchCommand command ) {
-            Node<Name, Object> node = getNode(command.getPath());
-            // Look up the new parent, which must exist ...
-            Path newPath = command.getNewPath();
-            Node<Name, Object> newParent = getNode(newPath.getParent());
-            copyNode(node, newParent, true, null, getExecutionContext());
-        }
-
-        @Override
-        public void execute( MoveBranchCommand command ) {
-            Node<Name, Object> node = getNode(command.getPath());
-            boolean recursive = true;
-            Name uuidProperty = getUuidPropertyName(getExecutionContext());
-            // Look up the new parent, which must exist ...
-            Path newPath = command.getNewPath();
-            Node<Name, Object> newParent = getNode(newPath.getParent());
-            copyNode(node, newParent, recursive, uuidProperty, getExecutionContext());
-
-            // Now delete the old node ...
-            Node<Name, Object> oldParent = node.getParent();
-            boolean removed = oldParent.removeChild(node.getFqn().getLastElement());
-            assert removed;
-        }
-
-        @Override
-        public void execute( RecordBranchCommand command ) {
-            Node<Name, Object> node = getNode(command.getPath());
-            recordNode(command, node);
-        }
-
-        protected void recordNode( RecordBranchCommand command,
-                                   Node<Name, Object> node ) {
-            // Record the properties ...
-            Map<Name, Object> dataMap = node.getData();
-            List<Property> properties = new LinkedList<Property>();
-            for (Map.Entry<Name, Object> data : dataMap.entrySet()) {
-                Name propertyName = data.getKey();
-                Object values = data.getValue();
-                Property property = propertyFactory.create(propertyName, values);
-                properties.add(property);
-            }
-            command.record(command.getPath(), properties);
-            // Now record the children ...
-            for (Node<Name, Object> child : node.getChildren()) {
-                recordNode(command, child);
-            }
-        }
-
-        protected Node<Name, Object> getNode( Path path ) {
-            return JBossCacheConnection.this.getNode(getExecutionContext(), path);
-        }
-
-    }
-
 }

Modified: trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectionTest.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectionTest.java	2008-10-23 18:42:49 UTC (rev 571)
+++ trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheConnectionTest.java	2008-10-23 18:46:32 UTC (rev 572)
@@ -31,9 +31,9 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.stub;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 import org.jboss.cache.Cache;
 import org.jboss.cache.CacheFactory;
 import org.jboss.cache.DefaultCacheFactory;
@@ -41,10 +41,11 @@
 import org.jboss.cache.Node;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
 import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.commands.basic.BasicCreateNodeCommand;
-import org.jboss.dna.graph.commands.basic.BasicGetNodeCommand;
 import org.jboss.dna.graph.connectors.BasicExecutionContext;
+import org.jboss.dna.graph.connectors.RepositoryConnectionFactory;
 import org.jboss.dna.graph.connectors.RepositorySourceListener;
 import org.jboss.dna.graph.properties.Name;
 import org.jboss.dna.graph.properties.NameFactory;
@@ -70,8 +71,11 @@
     private PathFactory pathFactory;
     private NameFactory nameFactory;
     private PropertyFactory propertyFactory;
+    private Graph graph;
     @Mock
     private JBossCacheSource source;
+    @Mock
+    private RepositoryConnectionFactory connectionFactory;
 
     @Before
     public void beforeEach() throws Exception {
@@ -84,8 +88,11 @@
         cacheFactory = new DefaultCacheFactory<Name, Object>();
         cache = cacheFactory.createCache();
         connection = new JBossCacheConnection(source, cache);
+        String sourceName = "the source name";
         stub(source.getUuidPropertyName()).toReturn(DnaLexicon.UUID.getString(context.getNamespaceRegistry()));
-        stub(source.getName()).toReturn("the source name");
+        stub(source.getName()).toReturn(sourceName);
+        stub(connectionFactory.createConnection(sourceName)).toReturn(connection);
+        graph = Graph.create(sourceName, connectionFactory, context);
     }
 
     @Test( expected = AssertionError.class )
@@ -151,21 +158,6 @@
     }
 
     @Test
-    public void shouldGetUuidPropertyNameFromSouceAndShouldNotChangeDuringLifetimeOfConnection() {
-        stub(source.getUuidPropertyName()).toReturn(DnaLexicon.UUID.getString(context.getNamespaceRegistry()));
-        Name name = connection.getUuidPropertyName(context);
-        verify(source).getUuidPropertyName();
-        assertThat(name.getLocalName(), is("uuid"));
-        assertThat(name.getNamespaceUri(), is(DnaLexicon.Namespace.URI));
-        stub(source.getUuidPropertyName()).toReturn("something else");
-        for (int i = 0; i != 10; ++i) {
-            Name name2 = connection.getUuidPropertyName(context);
-            assertThat(name2, is(sameInstance(name)));
-        }
-        verifyNoMoreInteractions(source);
-    }
-
-    @Test
     public void shouldGenerateUuid() {
         for (int i = 0; i != 100; ++i) {
             assertThat(connection.generateUuid(), is(notNullValue()));
@@ -227,7 +219,7 @@
     @Test
     public void shouldGetNodeIfItExistsInCache() {
         // Set up the cache with data ...
-        Name uuidProperty = connection.getUuidPropertyName(context);
+        Name uuidProperty = DnaLexicon.UUID;
         Path[] paths = {pathFactory.create("/a"), pathFactory.create("/a/b"), pathFactory.create("/a/b/c")};
         Path nonExistantPath = pathFactory.create("/a/d");
         UUID[] uuids = {UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID()};
@@ -251,7 +243,7 @@
     @Test
     public void shouldThrowExceptionWithLowestExistingNodeFromGetNodeIfTheNodeDoesNotExist() {
         // Set up the cache with data ...
-        Name uuidProperty = connection.getUuidPropertyName(context);
+        Name uuidProperty = DnaLexicon.UUID;
         Path[] paths = {pathFactory.create("/a"), pathFactory.create("/a/b"), pathFactory.create("/a/b/c")};
         Path nonExistantPath = pathFactory.create("/a/d");
         UUID[] uuids = {UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID()};
@@ -277,7 +269,7 @@
     @Test
     public void shouldCopyNode() {
         // Set up the cache with data ...
-        Name uuidProperty = connection.getUuidPropertyName(context);
+        Name uuidProperty = DnaLexicon.UUID;
         Path[] paths = {pathFactory.create("/a"), pathFactory.create("/a/b"), pathFactory.create("/a/b/c"),
             pathFactory.create("/a/d")};
         UUID[] uuids = {UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID()};
@@ -305,7 +297,9 @@
         assertThat(newNodeB, is(nullValue()));
         assertThat(newNodeC, is(nullValue()));
         // Copy node B and place under node D
-        assertThat(connection.copyNode(nodeB, nodeD, true, uuidProperty, context), is(2));
+        AtomicInteger count = new AtomicInteger();
+        connection.copyNode(nodeB, nodeD, true, uuidProperty, count, context);
+        assertThat(count.get(), is(2));
         newNodeB = cache.getNode(Fqn.fromList(newPathB.getSegmentsList()));
         newNodeC = cache.getNode(Fqn.fromList(newPathC.getSegmentsList()));
         assertThat(newNodeB, is(notNullValue()));
@@ -320,27 +314,21 @@
         // Set up the cache with some data, using different execute calls ...
         Property prop1 = propertyFactory.create(nameFactory.create("dna:prop1"), "value1");
         Property prop2 = propertyFactory.create(nameFactory.create("dna:prop2"), "value1");
-        Path pathA = pathFactory.create("/a");
-        BasicCreateNodeCommand createNode = new BasicCreateNodeCommand(pathA);
-        createNode.setProperties(prop1, prop2);
-        connection.execute(context, createNode);
-
+        graph.create("/a", prop1, prop2);
         for (int i = 0; i != 20; ++i) {
-            createNode = new BasicCreateNodeCommand(pathFactory.create("/a/b"));
-            createNode.setProperties(prop1, prop2);
-            connection.execute(context, createNode);
+            graph.create("/a/b", prop1, prop2);
         }
 
-        // Get the name that we'll use in later assertions ...
-        Name nameB = pathFactory.createSegment("b").getName();
-        assertThat(nameB.getLocalName(), is("b"));
-
         // Now verify the content ...
-        BasicGetNodeCommand getNode = new BasicGetNodeCommand(pathA);
-        connection.execute(context, getNode);
+        org.jboss.dna.graph.Node aNode = graph.getNodeAt("/a");
+        assertThat(aNode, is(notNullValue()));
+        assertThat(aNode.getPropertiesByName().get(prop1.getName()), is(prop1));
+        assertThat(aNode.getPropertiesByName().get(prop2.getName()), is(prop2));
+        assertThat(aNode.getChildren().size(), is(20));
         int index = 1;
-        for (Path.Segment segment : getNode.getChildren()) {
-            assertThat(segment.getName(), is(nameB));
+        for (Location childLocation : aNode.getChildren()) {
+            Path.Segment segment = childLocation.getPath().getLastSegment();
+            assertThat(segment.getName().getLocalName(), is("b"));
             assertThat(segment.hasIndex(), is(true));
             assertThat(segment.getIndex(), is(index));
             ++index;
@@ -353,36 +341,30 @@
         // Set up the cache with some data, using different execute calls ...
         Property prop1 = propertyFactory.create(nameFactory.create("dna:prop1"), "value1");
         Property prop2 = propertyFactory.create(nameFactory.create("dna:prop2"), "value1");
-        Path pathA = pathFactory.create("/a");
-        BasicCreateNodeCommand createNode = new BasicCreateNodeCommand(pathA);
-        createNode.setProperties(prop1, prop2);
-        connection.execute(context, createNode);
-
+        graph.create("/a", prop1, prop2);
         for (int i = 0; i != 20; ++i) {
             String path = i % 5 == 0 ? "/a/b" : "/a/c" + i;
-            createNode = new BasicCreateNodeCommand(pathFactory.create(path));
-            createNode.setProperties(prop1, prop2);
-            connection.execute(context, createNode);
+            graph.create(path, prop1, prop2);
         }
 
-        // Get the name that we'll use in later assertions ...
-        Name nameB = pathFactory.createSegment("b").getName();
-        assertThat(nameB.getLocalName(), is("b"));
-
         // Now verify the content ...
-        BasicGetNodeCommand getNode = new BasicGetNodeCommand(pathA);
-        connection.execute(context, getNode);
+        org.jboss.dna.graph.Node aNode = graph.getNodeAt("/a");
+        assertThat(aNode, is(notNullValue()));
+        assertThat(aNode.getPropertiesByName().get(prop1.getName()), is(prop1));
+        assertThat(aNode.getPropertiesByName().get(prop2.getName()), is(prop2));
+        assertThat(aNode.getChildren().size(), is(20));
         int index = 1;
-        for (Path.Segment segment : getNode.getChildren()) {
+        for (Location childLocation : aNode.getChildren()) {
+            Path.Segment segment = childLocation.getPath().getLastSegment();
             if (segment.getName().getLocalName().equals("b")) {
-                assertThat(segment.getName(), is(nameB));
+                assertThat(segment.getName().getLocalName(), is("b"));
                 assertThat(segment.hasIndex(), is(true));
                 assertThat(segment.getIndex(), is(index));
                 ++index;
             } else {
+                assertThat(segment.getName().getLocalName().startsWith("c"), is(true));
                 assertThat(segment.hasIndex(), is(false));
             }
         }
     }
-
 }




More information about the dna-commits mailing list