[dna-commits] DNA SVN: r1065 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory and 4 other directories.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Fri Jun 26 22:54:06 EDT 2009


Author: bcarothers
Date: 2009-06-26 22:54:06 -0400 (Fri, 26 Jun 2009)
New Revision: 1065

Added:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapNode.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepository.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositoryConnection.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositorySource.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapWorkspace.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/package-info.java
   trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java
Removed:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryNode.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryConnection.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
   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/JBossCacheLexicon.java
   trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java
   trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheWorkspaces.java
   trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessorTest.java
Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java
   trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java
Log:
DNA-470 Provide Base Set of Connector Classes for All Map-Based Connectors

Applied patch that creates a new MapRepository class (and associated classes) based on the original InMemoryRepository implementation and refactors the In-Memory connector and JBoss Cache connector to utilize the new MapRepository.


Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryNode.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryNode.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryNode.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -1,173 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of 
- * individual contributors. 
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.graph.connector.inmemory;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import net.jcip.annotations.NotThreadSafe;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.property.PropertyFactory;
-
-/**
- * @author Randall Hauch
- */
- at NotThreadSafe
-public class InMemoryNode {
-
-    private final UUID uuid;
-    private InMemoryNode parent;
-    private Path.Segment name;
-    private final Map<Name, Property> properties = new HashMap<Name, Property>();
-    private final LinkedList<InMemoryNode> children = new LinkedList<InMemoryNode>();
-    final Set<Name> existingNames = new HashSet<Name>();
-
-    public InMemoryNode( UUID uuid ) {
-        assert uuid != null;
-        this.uuid = uuid;
-    }
-
-    /**
-     * @return uuid
-     */
-    public UUID getUuid() {
-        return uuid;
-    }
-
-    /**
-     * @return name
-     */
-    public Path.Segment getName() {
-        return name;
-    }
-
-    /**
-     * @param name Sets name to the specified value.
-     */
-    protected void setName( Path.Segment name ) {
-        this.name = name;
-    }
-
-    /**
-     * @return parent
-     */
-    public InMemoryNode getParent() {
-        return parent;
-    }
-
-    /**
-     * @param parent Sets parent to the specified value.
-     */
-    protected void setParent( InMemoryNode parent ) {
-        this.parent = parent;
-    }
-
-    /**
-     * @return children
-     */
-    LinkedList<InMemoryNode> getChildren() {
-        return children;
-    }
-
-    /**
-     * @return properties
-     */
-    protected Map<Name, Property> getProperties() {
-        return properties;
-    }
-
-    public InMemoryNode setProperty( Property property ) {
-        if (property != null) {
-            this.properties.put(property.getName(), property);
-        }
-        return this;
-    }
-
-    public InMemoryNode setProperty( ExecutionContext context,
-                                     String name,
-                                     Object... values ) {
-        PropertyFactory propertyFactory = context.getPropertyFactory();
-        Name propertyName = context.getValueFactories().getNameFactory().create(name);
-        return setProperty(propertyFactory.create(propertyName, values));
-    }
-
-    public Property getProperty( ExecutionContext context,
-                                 String name ) {
-        Name propertyName = context.getValueFactories().getNameFactory().create(name);
-        return getProperty(propertyName);
-    }
-
-    public Property getProperty( Name name ) {
-        return this.properties.get(name);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see java.lang.Object#hashCode()
-     */
-    @Override
-    public int hashCode() {
-        return uuid.hashCode();
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see java.lang.Object#equals(java.lang.Object)
-     */
-    @Override
-    public boolean equals( Object obj ) {
-        if (obj == this) return true;
-        if (obj instanceof InMemoryNode) {
-            InMemoryNode that = (InMemoryNode)obj;
-            if (!this.getUuid().equals(that.getUuid())) return false;
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see java.lang.Object#toString()
-     */
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        if (this.name == null) {
-            sb.append("");
-        } else {
-            sb.append(this.name);
-        }
-        sb.append(" (").append(uuid).append(")");
-        return sb.toString();
-    }
-}

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -23,420 +23,80 @@
  */
 package org.jboss.dna.graph.connector.inmemory;
 
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
 import java.util.Map;
-import java.util.Set;
 import java.util.UUID;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 import net.jcip.annotations.GuardedBy;
 import net.jcip.annotations.NotThreadSafe;
-import org.jboss.dna.common.util.CheckArg;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.map.AbstractMapWorkspace;
+import org.jboss.dna.graph.connector.map.MapNode;
+import org.jboss.dna.graph.connector.map.MapRepository;
+import org.jboss.dna.graph.connector.map.MapWorkspace;
 import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.PathFactory;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.property.PropertyFactory;
-import org.jboss.dna.graph.property.PropertyType;
-import org.jboss.dna.graph.property.Reference;
-import org.jboss.dna.graph.property.UuidFactory;
-import org.jboss.dna.graph.property.ValueFactory;
-import org.jboss.dna.graph.property.basic.RootPath;
-import org.jboss.dna.graph.request.CreateWorkspaceRequest.CreateConflictBehavior;
 
 /**
  * @author Randall Hauch
  */
 @NotThreadSafe
-public class InMemoryRepository {
+public class InMemoryRepository extends MapRepository {
 
-    protected final ReadWriteLock lock = new ReentrantReadWriteLock();
-    protected final UUID rootNodeUuid;
-    private final String sourceName;
-    private final String defaultWorkspaceName;
-    private final Map<String, Workspace> workspaces = new HashMap<String, Workspace>();
-
     public InMemoryRepository( String sourceName,
                                UUID rootNodeUuid ) {
-        this(sourceName, rootNodeUuid, null);
+        super(sourceName, rootNodeUuid, null);
+        initialize();
     }
 
     public InMemoryRepository( String sourceName,
                                UUID rootNodeUuid,
                                String defaultWorkspaceName ) {
-        CheckArg.isNotEmpty(sourceName, "sourceName");
-        CheckArg.isNotNull(rootNodeUuid, "rootNodeUUID");
-        this.rootNodeUuid = rootNodeUuid;
-        this.sourceName = sourceName;
-        this.defaultWorkspaceName = defaultWorkspaceName != null ? defaultWorkspaceName : "";
-        // Create the default workspace ...
-        workspaces.put(this.defaultWorkspaceName, new Workspace(this.defaultWorkspaceName));
+        super(sourceName, rootNodeUuid, defaultWorkspaceName);
+        initialize();
     }
 
-    /**
-     * @return sourceName
-     */
-    public String getSourceName() {
-        return sourceName;
-    }
-
-    /**
-     * @return lock
-     */
-    public ReadWriteLock getLock() {
-        return lock;
-    }
-
     @GuardedBy( "getLock()" )
-    public Set<String> getWorkspaceNames() {
-        return workspaces.keySet();
+    protected MapWorkspace createWorkspace( ExecutionContext context,
+                                            String name ) {
+        return new Workspace(this, name);
     }
 
-    @GuardedBy( "getLock()" )
-    public Workspace getWorkspace( ExecutionContext context,
-                                   String name ) {
-        if (name == null) name = defaultWorkspaceName;
-        return workspaces.get(name);
-    }
+    protected class Workspace extends AbstractMapWorkspace {
+        private final Map<UUID, MapNode> nodesByUuid = new HashMap<UUID, MapNode>();
 
-    @GuardedBy( "getLock()" )
-    public Workspace createWorkspace( ExecutionContext context,
-                                      String name,
-                                      CreateConflictBehavior behavior ) {
-        String newName = name;
-        boolean conflictingName = workspaces.containsKey(newName);
-        if (conflictingName) {
-            switch (behavior) {
-                case DO_NOT_CREATE:
-                    return null;
-                case CREATE_WITH_ADJUSTED_NAME:
-                    int counter = 0;
-                    do {
-                        newName = name + (++counter);
-                    } while (workspaces.containsKey(newName));
-                    break;
-            }
-        }
-        assert workspaces.containsKey(newName) == false;
-        Workspace workspace = new Workspace(newName);
-        workspaces.put(newName, workspace);
-        return workspace;
-    }
+        public Workspace( MapRepository repository,
+                          String name ) {
+            super(repository, name);
 
-    @GuardedBy( "getLock()" )
-    public Workspace createWorkspace( ExecutionContext context,
-                                      String name,
-                                      CreateConflictBehavior existingWorkspaceBehavior,
-                                      String nameOfWorkspaceToClone ) {
-        Workspace workspace = createWorkspace(context, name, existingWorkspaceBehavior);
-        if (workspace == null) {
-            // Unable to create because of a duplicate name ...
-            return null;
+            initialize();
         }
-        Workspace original = getWorkspace(context, nameOfWorkspaceToClone);
-        if (original != null) {
-            // Copy the properties of the root node ...
-            InMemoryNode root = workspace.getRoot();
-            InMemoryNode origRoot = original.getRoot();
-            root.getProperties().clear();
-            root.getProperties().putAll(origRoot.getProperties());
 
-            // Loop over each child and call this method to copy the immediate children (and below).
-            // Note that this makes the copy have the same UUID as the original.
-            for (InMemoryNode originalNode : origRoot.getChildren()) {
-                original.copyNode(context, originalNode, workspace, root, originalNode.getName().getName(), true, null);
-            }
-        }
-        return workspace;
-    }
-
-    @GuardedBy( "getLock()" )
-    public boolean destroyWorkspace( String name ) {
-        return workspaces.remove(name) != null;
-    }
-
-    protected class Workspace {
-        private final Map<UUID, InMemoryNode> nodesByUuid = new HashMap<UUID, InMemoryNode>();
-        private final String name;
-
-        protected Workspace( String name ) {
-            assert name != null;
-            this.name = name;
-            // Create the root node ...
-            InMemoryNode root = new InMemoryNode(rootNodeUuid);
-            nodesByUuid.put(root.getUuid(), root);
-        }
-
-        /**
-         * @return name
-         */
-        public String getName() {
-            return name;
-        }
-
-        public InMemoryNode getRoot() {
-            return nodesByUuid.get(rootNodeUuid);
-        }
-
-        public InMemoryNode getNode( UUID uuid ) {
-            assert uuid != null;
-            return nodesByUuid.get(uuid);
-        }
-
-        protected Map<UUID, InMemoryNode> getNodesByUuid() {
-            return nodesByUuid;
-        }
-
-        public InMemoryNode getNode( ExecutionContext context,
-                                     String path ) {
-            assert context != null;
-            assert path != null;
-            return getNode(context.getValueFactories().getPathFactory().create(path));
-        }
-
-        /**
-         * Find a node with the given path.
-         * 
-         * @param path the path to the node; may not be null
-         * @return the node with the path, or null if the node does not exist
-         */
-        public InMemoryNode getNode( Path path ) {
-            assert path != null;
-            InMemoryNode node = getRoot();
-            for (Path.Segment segment : path) {
-                InMemoryNode desiredChild = null;
-                for (InMemoryNode child : node.getChildren()) {
-                    if (child == null) continue;
-                    Path.Segment childName = child.getName();
-                    if (childName == null) continue;
-                    if (childName.equals(segment)) {
-                        desiredChild = child;
-                        break;
-                    }
-                }
-                if (desiredChild != null) {
-                    node = desiredChild;
-                } else {
-                    return null;
-                }
-            }
-            return node;
-        }
-
-        /**
-         * Returns the absolute path to the given node
-         * 
-         * @param pathFactory the path factory to use to create the path from the list of names of all of the nodes on the path
-         *        from the root node to the given node
-         * @param node the node for which the path should be returned
-         * @return the absolute path to the given node
-         */
-        Path pathFor( PathFactory pathFactory,
-                      InMemoryNode node ) {
+        protected void addNodeToMap( MapNode node ) {
             assert node != null;
-            assert pathFactory != null;
-
-            LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
-            InMemoryNode root = getRoot();
-
-            do {
-                segments.addFirst(node.getName());
-                node = node.getParent();
-            } while (!node.equals(root));
-
-            return pathFactory.createAbsolutePath(segments);
+            assert nodesByUuid != null;
+            nodesByUuid.put(node.getUuid(), node);
         }
 
-        /**
-         * Find the lowest existing node along the path.
-         * 
-         * @param path the path to the node; may not be null
-         * @return the lowest existing node along the path, or the root node if no node exists on the path
-         */
-        public Path getLowestExistingPath( Path path ) {
-            assert path != null;
-            InMemoryNode node = getRoot();
-            int segmentNumber = 0;
-            for (Path.Segment segment : path) {
-                InMemoryNode desiredChild = null;
-                for (InMemoryNode child : node.getChildren()) {
-                    if (child == null) continue;
-                    Path.Segment childName = child.getName();
-                    if (childName == null) continue;
-                    if (childName.equals(segment)) {
-                        desiredChild = child;
-                        break;
-                    }
-                }
-                if (desiredChild != null) {
-                    node = desiredChild;
-                } else {
-                    return path.subpath(0, segmentNumber);
-                }
-                ++segmentNumber;
-            }
-            return RootPath.INSTANCE;
+        protected MapNode removeNodeFromMap( UUID nodeUuid ) {
+            assert nodeUuid != null;
+            return nodesByUuid.remove(nodeUuid);
         }
 
-        public void removeNode( ExecutionContext context,
-                                InMemoryNode node ) {
-            assert context != null;
-            assert node != null;
-            if (getRoot().equals(node)) {
-                nodesByUuid.clear();
-                // Create the root node ...
-                InMemoryNode root = new InMemoryNode(rootNodeUuid);
-                nodesByUuid.put(root.getUuid(), root);
-                return;
-            }
-            InMemoryNode parent = node.getParent();
-            assert parent != null;
-            parent.getChildren().remove(node);
-            correctSameNameSiblingIndexes(context, parent, node.getName().getName());
-            removeUuidReference(node);
+        protected void removeAllNodesFromMap() {
+            nodesByUuid.clear();
         }
 
-        protected void removeUuidReference( InMemoryNode node ) {
-            nodesByUuid.remove(node.getUuid());
-            for (InMemoryNode child : node.getChildren()) {
-                removeUuidReference(child);
-            }
+        public MapNode getNode( UUID nodeUuid ) {
+            assert nodeUuid != null;
+            return nodesByUuid.get(nodeUuid);
         }
 
         /**
-         * Create a node at the supplied path. The parent of the new node must already exist.
-         * 
-         * @param context the environment; may not be null
-         * @param pathToNewNode the path to the new node; may not be null
-         * @return the new node (or root if the path specified the root)
-         */
-        public InMemoryNode createNode( ExecutionContext context,
-                                        String pathToNewNode ) {
-            assert context != null;
-            assert pathToNewNode != null;
-            Path path = context.getValueFactories().getPathFactory().create(pathToNewNode);
-            if (path.isRoot()) return getRoot();
-            Path parentPath = path.getParent();
-            InMemoryNode parentNode = getNode(parentPath);
-            Name name = path.getLastSegment().getName();
-            return createNode(context, parentNode, name, null);
-        }
-
-        /**
-         * Create a new node with the supplied name, as a child of the supplied parent.
-         * 
-         * @param context the execution context
-         * @param parentNode the parent node; may not be null
-         * @param name the name; may not be null
-         * @param uuid the UUID of the node, or null if the UUID is to be generated
-         * @return the new node
-         */
-        public InMemoryNode createNode( ExecutionContext context,
-                                        InMemoryNode parentNode,
-                                        Name name,
-                                        UUID uuid ) {
-            assert context != null;
-            assert name != null;
-            if (parentNode == null) parentNode = getRoot();
-            if (uuid == null) uuid = UUID.randomUUID();
-            InMemoryNode node = new InMemoryNode(uuid);
-            nodesByUuid.put(node.getUuid(), node);
-            node.setParent(parentNode);
-            // Find the last node with this same name ...
-            int nextIndex = 1;
-            if (parentNode.existingNames.contains(name)) {
-                ListIterator<InMemoryNode> iter = parentNode.getChildren().listIterator(parentNode.getChildren().size());
-                while (iter.hasPrevious()) {
-                    InMemoryNode prev = iter.previous();
-                    if (prev.getName().getName().equals(name)) {
-                        nextIndex = prev.getName().getIndex() + 1;
-                        break;
-                    }
-                }
-            }
-            Path.Segment newName = context.getValueFactories().getPathFactory().createSegment(name, nextIndex);
-            node.setName(newName);
-            parentNode.getChildren().add(node);
-            parentNode.existingNames.add(name);
-            return node;
-        }
-
-        /**
-         * Move the supplied node to the new parent. This method automatically removes the node from its existing parent, and also
-         * correctly adjusts the {@link Path.Segment#getIndex() index} to be correct in the new parent.
-         * 
-         * @param context
-         * @param node the node to be moved; may not be the {@link Workspace#getRoot() root}
-         * @param desiredNewName the new name for the node, if it is to be changed; may be null
-         * @param newWorkspace the workspace containing the new parent node
-         * @param newParent the new parent; may not be the {@link Workspace#getRoot() root}
-         * @param beforeNode the node before which this new node should be placed
-         */
-        public void moveNode( ExecutionContext context,
-                              InMemoryNode node,
-                              Name desiredNewName,
-                              Workspace newWorkspace,
-                              InMemoryNode newParent,
-                              InMemoryNode beforeNode ) {
-            assert context != null;
-            assert newParent != null;
-            assert node != null;
-            // Why was this restriction here? -- BRC
-            // assert newWorkspace.getRoot().equals(newParent) != true;
-            assert this.getRoot().equals(node) != true;
-            InMemoryNode oldParent = node.getParent();
-            Name oldName = node.getName().getName();
-            if (oldParent != null) {
-                boolean removed = oldParent.getChildren().remove(node);
-                assert removed == true;
-                node.setParent(null);
-                correctSameNameSiblingIndexes(context, oldParent, oldName);
-            }
-            node.setParent(newParent);
-            Name newName = oldName;
-            if (desiredNewName != null) {
-                newName = desiredNewName;
-                node.setName(context.getValueFactories().getPathFactory().createSegment(desiredNewName, 1));
-            }
-
-            if (beforeNode == null) {
-                newParent.getChildren().add(node);
-            } else {
-                int index = newParent.getChildren().indexOf(beforeNode);
-                newParent.getChildren().add(index, node);
-            }
-            correctSameNameSiblingIndexes(context, newParent, newName);
-
-            // If the node was moved to a new workspace...
-            if (!this.equals(newWorkspace)) {
-                // We need to remove the node from this workspace's map of nodes ...
-                this.moveNodeToWorkspace(node, newWorkspace);
-            }
-        }
-
-        protected void moveNodeToWorkspace( InMemoryNode node,
-                                            Workspace newWorkspace ) {
-            assert this.nodesByUuid.containsKey(node.getUuid());
-            assert !newWorkspace.nodesByUuid.containsKey(node.getUuid());
-
-            this.nodesByUuid.remove(node.getUuid());
-            newWorkspace.nodesByUuid.put(node.getUuid(), node);
-            for (InMemoryNode child : node.getChildren()) {
-                moveNodeToWorkspace(child, newWorkspace);
-            }
-        }
-
-        /**
          * This should copy the subgraph given by the original node and place the new copy under the supplied new parent. Note
          * that internal references between nodes within the original subgraph must be reflected as internal nodes within the new
          * subgraph.
+         * <p>
+         * This method is trivially overridden for testing purposes.
+         * </p>
          * 
          * @param context the context; may not be null
          * @param original the node to be copied; may not be null
@@ -448,152 +108,24 @@
          *        null if the UUIDs are to be maintained
          * @return the new node, which is the top of the new subgraph
          */
-        public InMemoryNode copyNode( ExecutionContext context,
-                                      InMemoryNode original,
-                                      Workspace newWorkspace,
-                                      InMemoryNode newParent,
-                                      Name desiredName,
-                                      boolean recursive,
-                                      Map<UUID, UUID> oldToNewUuids ) {
-            assert context != null;
-            assert original != null;
-            assert newParent != null;
-            assert newWorkspace != null;
-            boolean reuseUuids = oldToNewUuids == null;
-
-            // Get or create the new node ...
-            Name childName = desiredName != null ? desiredName : original.getName().getName();
-            UUID uuidForCopy = reuseUuids ? original.getUuid() : UUID.randomUUID();
-            InMemoryNode copy = newWorkspace.createNode(context, newParent, childName, uuidForCopy);
-            if (!reuseUuids) {
-                assert oldToNewUuids != null;
-                oldToNewUuids.put(original.getUuid(), copy.getUuid());
-            }
-
-            // Copy the properties ...
-            copy.getProperties().clear();
-            copy.getProperties().putAll(original.getProperties());
-            if (recursive) {
-                // Loop over each child and call this method ...
-                for (InMemoryNode child : original.getChildren()) {
-                    copyNode(context, child, newWorkspace, copy, null, true, oldToNewUuids);
-                }
-            }
-
-            if (!reuseUuids) {
-                assert oldToNewUuids != null;
-                // Now, adjust any references in the new subgraph to objects in the original subgraph
-                // (because they were internal references, and need to be internal to the new subgraph)
-                PropertyFactory propertyFactory = context.getPropertyFactory();
-                UuidFactory uuidFactory = context.getValueFactories().getUuidFactory();
-                ValueFactory<Reference> referenceFactory = context.getValueFactories().getReferenceFactory();
-                for (Map.Entry<UUID, UUID> oldToNew : oldToNewUuids.entrySet()) {
-                    InMemoryNode oldNode = this.getNode(oldToNew.getKey());
-                    InMemoryNode newNode = newWorkspace.getNode(oldToNew.getValue());
-                    assert oldNode != null;
-                    assert newNode != null;
-                    // Iterate over the properties of the new ...
-                    for (Map.Entry<Name, Property> entry : newNode.getProperties().entrySet()) {
-                        Property property = entry.getValue();
-                        // Now see if any of the property values are references ...
-                        List<Object> newValues = new ArrayList<Object>();
-                        boolean foundReference = false;
-                        for (Iterator<?> iter = property.getValues(); iter.hasNext();) {
-                            Object value = iter.next();
-                            PropertyType type = PropertyType.discoverType(value);
-                            if (type == PropertyType.REFERENCE) {
-                                UUID oldReferencedUuid = uuidFactory.create(value);
-                                UUID newReferencedUuid = oldToNewUuids.get(oldReferencedUuid);
-                                if (newReferencedUuid != null) {
-                                    newValues.add(referenceFactory.create(newReferencedUuid));
-                                    foundReference = true;
-                                }
-                            } else {
-                                newValues.add(value);
-                            }
-                        }
-                        // If we found at least one reference, we have to build a new Property object ...
-                        if (foundReference) {
-                            Property newProperty = propertyFactory.create(property.getName(), newValues);
-                            entry.setValue(newProperty);
-                        }
-                    }
-                }
-            }
-
-            return copy;
-        }
-
-        public Set<UUID> getUuidsUnderNode( InMemoryNode node ) {
-            Set<UUID> uuids = new HashSet<UUID>();
-            uuidsUnderNode(node, uuids);
-
-            return uuids;
-        }
-
-        private void uuidsUnderNode( InMemoryNode node,
-                                     Set<UUID> accumulator ) {
-            accumulator.add(node.getUuid());
-
-            for (InMemoryNode child : node.getChildren()) {
-                uuidsUnderNode(child, accumulator);
-            }
-        }
-
-        protected void correctSameNameSiblingIndexes( ExecutionContext context,
-                                                      InMemoryNode parentNode,
-                                                      Name name ) {
-            if (parentNode == null) return;
-            // Look for the highest existing index ...
-            List<InMemoryNode> childrenWithSameNames = new LinkedList<InMemoryNode>();
-            for (InMemoryNode child : parentNode.getChildren()) {
-                if (child.getName().getName().equals(name)) childrenWithSameNames.add(child);
-            }
-            if (childrenWithSameNames.size() == 0) return;
-            if (childrenWithSameNames.size() == 1) {
-                InMemoryNode childWithSameName = childrenWithSameNames.get(0);
-                Path.Segment newName = context.getValueFactories().getPathFactory().createSegment(name, Path.DEFAULT_INDEX);
-                childWithSameName.setName(newName);
-                return;
-            }
-            int index = 1;
-            for (InMemoryNode childWithSameName : childrenWithSameNames) {
-                Path.Segment segment = childWithSameName.getName();
-                if (segment.getIndex() != index) {
-                    Path.Segment newName = context.getValueFactories().getPathFactory().createSegment(name, index);
-                    childWithSameName.setName(newName);
-                }
-                ++index;
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         * 
-         * @see java.lang.Object#equals(java.lang.Object)
-         */
         @Override
-        public boolean equals( Object obj ) {
-            if (obj == this) return true;
-            if (obj instanceof Workspace) {
-                Workspace that = (Workspace)obj;
-                // Assume the workspaces are in the same repository ...
-                if (!this.name.equals(that.name)) return false;
-                return true;
-            }
-            return false;
+        protected MapNode copyNode( ExecutionContext context,
+                                    MapNode original,
+                                    MapWorkspace newWorkspace,
+                                    MapNode newParent,
+                                    Name desiredName,
+                                    boolean recursive,
+                                    Map<UUID, UUID> oldToNewUuids ) {
+            return super.copyNode(context, original, newWorkspace, newParent, desiredName, recursive, oldToNewUuids);
         }
 
         /**
-         * {@inheritDoc}
+         * Method added to support testing
          * 
-         * @see java.lang.Object#toString()
+         * @return the number of nodes in the backing map
          */
-        @Override
-        public String toString() {
-            return InMemoryRepository.this.getSourceName() + "/" + this.getName();
+        final int size() {
+            return nodesByUuid.size();
         }
-
     }
-
 }

Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryConnection.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryConnection.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryConnection.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -1,135 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of 
- * individual contributors. 
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.graph.connector.inmemory;
-
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-import javax.transaction.xa.XAResource;
-import org.jboss.dna.common.statistic.Stopwatch;
-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.connector.RepositoryConnection;
-import org.jboss.dna.graph.connector.RepositorySourceException;
-import org.jboss.dna.graph.request.Request;
-import org.jboss.dna.graph.request.processor.RequestProcessor;
-
-/**
- * @author Randall Hauch
- */
-public class InMemoryRepositoryConnection implements RepositoryConnection {
-
-    private final InMemoryRepositorySource source;
-    private final InMemoryRepository repository;
-
-    InMemoryRepositoryConnection( InMemoryRepositorySource source,
-                                  InMemoryRepository repository ) {
-        assert source != null;
-        assert repository != null;
-        this.source = source;
-        this.repository = repository;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String getSourceName() {
-        return source.getName();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public CachePolicy getDefaultCachePolicy() {
-        return source.getDefaultCachePolicy();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public XAResource getXAResource() {
-        return null;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean ping( long time,
-                         TimeUnit unit ) {
-        return true;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void close() {
-        // do nothing
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.connector.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
-     *      org.jboss.dna.graph.request.Request)
-     */
-    public void execute( ExecutionContext context,
-                         Request request ) throws RepositorySourceException {
-        Logger logger = context.getLogger(getClass());
-        Stopwatch sw = null;
-        if (logger.isTraceEnabled()) {
-            sw = new Stopwatch();
-            sw.start();
-        }
-        // Do any commands update/write?
-        RequestProcessor processor = new InMemoryRequestProcessor(context, this.repository, this.source.getRepositoryContext());
-
-        Lock lock = request.isReadOnly() ? repository.getLock().readLock() : repository.getLock().writeLock();
-        lock.lock();
-        try {
-            // Obtain the lock and execute the commands ...
-            processor.process(request);
-        } finally {
-            try {
-                processor.close();
-            } finally {
-                lock.unlock();
-            }
-        }
-        if (logger.isTraceEnabled()) {
-            assert sw != null;
-            sw.stop();
-            logger.trace("InMemoryRepositoryConnection.execute(...) took " + sw.getTotalDuration());
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see java.lang.Object#toString()
-     */
-    @Override
-    public String toString() {
-        return "Connection to the \"" + getSourceName() + "\" in-memory repository";
-    }
-}

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -52,6 +52,8 @@
 import org.jboss.dna.graph.connector.RepositorySource;
 import org.jboss.dna.graph.connector.RepositorySourceCapabilities;
 import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.map.MapRepositoryConnection;
+import org.jboss.dna.graph.connector.map.MapRepositorySource;
 
 /**
  * A {@link RepositorySource} for an in-memory repository. Each {@link InMemoryRepositorySource} instance contains its own
@@ -59,7 +61,7 @@
  * 
  * @author Randall Hauch
  */
-public class InMemoryRepositorySource implements RepositorySource, ObjectFactory {
+public class InMemoryRepositorySource implements MapRepositorySource, ObjectFactory {
 
     /**
      * The initial version is 1
@@ -258,7 +260,7 @@
         if (repository == null) {
             repository = new InMemoryRepository(name, rootNodeUuid, defaultWorkspaceName);
         }
-        return new InMemoryRepositoryConnection(this, repository);
+        return new MapRepositoryConnection(this, repository);
     }
 
     /**

Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -1,498 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of 
- * individual contributors.
- *
- * Unless otherwise indicated, all code in JBoss DNA is licensed
- * to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- * 
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.graph.connector.inmemory;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import org.jboss.dna.common.i18n.I18n;
-import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.graph.DnaLexicon;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.GraphI18n;
-import org.jboss.dna.graph.JcrLexicon;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.connector.RepositoryContext;
-import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.NamespaceRegistry;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.PathFactory;
-import org.jboss.dna.graph.property.PathNotFoundException;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.property.PropertyFactory;
-import org.jboss.dna.graph.property.Path.Segment;
-import org.jboss.dna.graph.request.CloneWorkspaceRequest;
-import org.jboss.dna.graph.request.CopyBranchRequest;
-import org.jboss.dna.graph.request.CreateNodeRequest;
-import org.jboss.dna.graph.request.CreateWorkspaceRequest;
-import org.jboss.dna.graph.request.DeleteBranchRequest;
-import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
-import org.jboss.dna.graph.request.GetWorkspacesRequest;
-import org.jboss.dna.graph.request.InvalidWorkspaceException;
-import org.jboss.dna.graph.request.MoveBranchRequest;
-import org.jboss.dna.graph.request.ReadAllChildrenRequest;
-import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
-import org.jboss.dna.graph.request.Request;
-import org.jboss.dna.graph.request.UpdatePropertiesRequest;
-import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
-import org.jboss.dna.graph.request.processor.RequestProcessor;
-
-/**
- * A {@link RequestProcessor} implementation that operates on an {@link InMemoryRepository} and its
- * {@link InMemoryRepository.Workspace workspaces}.
- */
-public class InMemoryRequestProcessor extends RequestProcessor {
-    private final PathFactory pathFactory;
-    private final PropertyFactory propertyFactory;
-    private final InMemoryRepository repository;
-
-    protected InMemoryRequestProcessor( ExecutionContext context,
-                                        InMemoryRepository repository,
-                                        RepositoryContext repositoryContext ) {
-        super(repository.getSourceName(), context, repositoryContext != null ? repositoryContext.getObserver() : null);
-        this.repository = repository;
-        pathFactory = context.getValueFactories().getPathFactory();
-        propertyFactory = context.getPropertyFactory();
-    }
-
-    @Override
-    public void process( ReadAllChildrenRequest request ) {
-        InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace());
-        InMemoryNode node = getTargetNode(workspace, request, request.of());
-        if (node == null) return;
-        Location actualLocation = getActualLocation(request.of().getPath(), node);
-        Path path = actualLocation.getPath();
-        // Get the names of the children ...
-        List<InMemoryNode> children = node.getChildren();
-        for (InMemoryNode child : children) {
-            Segment childName = child.getName();
-            Path childPath = pathFactory.create(path, childName);
-            request.addChild(childPath, propertyFactory.create(DnaLexicon.UUID, child.getUuid()));
-        }
-        request.setActualLocationOfNode(actualLocation);
-        setCacheableInfo(request);
-    }
-
-    @Override
-    public void process( ReadAllPropertiesRequest request ) {
-        InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace());
-        InMemoryNode node = getTargetNode(workspace, request, request.at());
-        if (node == null) return;
-        // Get the properties of the node ...
-        Location actualLocation = getActualLocation(request.at().getPath(), node);
-        request.addProperty(propertyFactory.create(DnaLexicon.UUID, node.getUuid()));
-        for (Property property : node.getProperties().values()) {
-            request.addProperty(property);
-        }
-        request.setActualLocationOfNode(actualLocation);
-        setCacheableInfo(request);
-    }
-
-    @Override
-    public void process( CopyBranchRequest request ) {
-        InMemoryRepository.Workspace workspace = getWorkspace(request, request.fromWorkspace());
-        InMemoryRepository.Workspace newWorkspace = getWorkspace(request, request.intoWorkspace());
-        if (workspace == null || newWorkspace == null) return;
-        InMemoryNode node = getTargetNode(workspace, request, request.from());
-        if (node == null) return;
-
-        Map<UUID, UUID> copyMap = null;
-        Set<UUID> uuidsInFromBranch = null;
-
-        switch (request.uuidConflictBehavior()) {
-            case ALWAYS_CREATE_NEW_UUID:
-
-                /*
-                 * The copyNode method uses the presence of a non-null map as an indicator that new UUIDs should be created
-                 * during the copy operation
-                 */
-                copyMap = new HashMap<UUID, UUID>();
-                break;
-            case REPLACE_EXISTING_NODE:
-                uuidsInFromBranch = workspace.getUuidsUnderNode(node);
-
-                for (UUID uuid : uuidsInFromBranch) {
-                    InMemoryNode existing;
-                    if (null != (existing = newWorkspace.getNode(uuid))) {
-                        newWorkspace.removeNode(this.getExecutionContext(), existing);
-                    }
-                }
-                break;
-            case THROW_EXCEPTION:
-                uuidsInFromBranch = workspace.getUuidsUnderNode(node);
-
-                for (UUID uuid : uuidsInFromBranch) {
-                    InMemoryNode existing;
-                    if (null != (existing = newWorkspace.getNode(uuid))) {
-                        NamespaceRegistry namespaces = this.getExecutionContext().getNamespaceRegistry();
-                        String path = newWorkspace.pathFor(pathFactory, existing).getString(namespaces);
-                        request.setError(new UuidAlreadyExistsException(this.getSourceName(), uuid, path, newWorkspace.getName()));
-                        return;
-                    }
-                }
-                break;
-
-            default:
-                throw new IllegalStateException("Unexpected UUID conflict behavior: " + request.uuidConflictBehavior());
-        }
-
-        // Look up the new parent, which must exist ...
-        Path newParentPath = request.into().getPath();
-        Name desiredName = request.desiredName();
-        InMemoryNode newParent = newWorkspace.getNode(newParentPath);
-        InMemoryNode newNode = workspace.copyNode(getExecutionContext(),
-                                                  node,
-                                                  newWorkspace,
-                                                  newParent,
-                                                  desiredName,
-                                                  true,
-                                                  copyMap);
-        Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, newNode.getName());
-        Location oldLocation = getActualLocation(request.from().getPath(), node);
-        Location newLocation = Location.create(newPath, newNode.getUuid());
-        request.setActualLocations(oldLocation, newLocation);
-        recordChange(request);
-    }
-
-    @Override
-    public void process( CreateNodeRequest request ) {
-        InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace());
-        if (workspace == null) return;
-        Path parent = request.under().getPath();
-        CheckArg.isNotNull(parent, "request.under().getPath()");
-        InMemoryNode node = null;
-        // Look up the parent node, which must exist ...
-        // System.err.println(request.toString());
-        InMemoryNode parentNode = workspace.getNode(parent);
-        if (parentNode == null) {
-            Path lowestExisting = workspace.getLowestExistingPath(parent);
-            request.setError(new PathNotFoundException(request.under(), lowestExisting,
-                                                       GraphI18n.inMemoryNodeDoesNotExist.text(parent)));
-            return;
-        }
-        UUID uuid = null;
-        for (Property property : request.properties()) {
-            if (property.getName().equals(DnaLexicon.UUID) || property.getName().equals(JcrLexicon.UUID)) {
-                uuid = getExecutionContext().getValueFactories().getUuidFactory().create(property.getValues().next());
-                break;
-            }
-        }
-        switch (request.conflictBehavior()) {
-            case APPEND:
-            case DO_NOT_REPLACE:
-                node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid);
-                break;
-            case REPLACE:
-                // See if the node already exists (this doesn't record an error on the request) ...
-                node = getTargetNode(workspace, null, Location.create(pathFactory.create(parent, request.named()), uuid));
-                if (node != null) {
-                    workspace.removeNode(getExecutionContext(), node);
-                }
-                node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid);
-                break;
-            case UPDATE:
-                // See if the node already exists (this doesn't record an error on the request) ...
-                node = getTargetNode(workspace, null, Location.create(pathFactory.create(parent, request.named()), uuid));
-                if (node == null) {
-                    node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid);
-                } // otherwise, we found it and we're setting any properties below
-                break;
-        }
-        assert node != null;
-        Path path = getExecutionContext().getValueFactories().getPathFactory().create(parent, node.getName());
-        // Now add the properties to the supplied node ...
-        for (Property property : request.properties()) {
-            Name propName = property.getName();
-            if (property.size() == 0) {
-                node.getProperties().remove(propName);
-                continue;
-            }
-            if (!propName.equals(DnaLexicon.UUID)) {
-                node.getProperties().put(propName, property);
-            }
-        }
-        Location actualLocation = getActualLocation(path, node);
-        request.setActualLocationOfNode(actualLocation);
-        recordChange(request);
-    }
-
-    @Override
-    public void process( DeleteBranchRequest request ) {
-        InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace());
-        if (workspace == null) return;
-        InMemoryNode node = getTargetNode(workspace, request, request.at());
-        if (node == null) return;
-        workspace.removeNode(getExecutionContext(), node);
-        Location actualLocation = getActualLocation(request.at().getPath(), node);
-        request.setActualLocationOfNode(actualLocation);
-        recordChange(request);
-    }
-
-    @Override
-    public void process( MoveBranchRequest request ) {
-        InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace());
-        if (workspace == null) return;
-
-        InMemoryNode beforeNode = request.before() != null ? getTargetNode(workspace, request, request.before()) : null;
-        InMemoryNode node = getTargetNode(workspace, request, request.from());
-        if (node == null) return;
-        // Look up the new parent, which must exist ...
-        Path newParentPath;
-
-        if (request.into() != null) {
-            newParentPath = request.into().getPath();
-        } else {
-            // into or before cannot both be null
-            assert beforeNode != null;
-
-            // Build the path from the before node to the root.
-            LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
-            InMemoryNode current = beforeNode.getParent();
-            while (current != workspace.getRoot()) {
-                segments.addFirst(current.getName());
-                current = current.getParent();
-            }
-            newParentPath = getExecutionContext().getValueFactories().getPathFactory().createAbsolutePath(segments);
-        }
-
-        InMemoryNode newParent = workspace.getNode(newParentPath);
-        workspace.moveNode(getExecutionContext(), node, request.desiredName(), workspace, newParent, beforeNode);
-        assert node.getParent() == newParent;
-        Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName());
-        Location oldLocation = getActualLocation(request.from().getPath(), node);
-        Location newLocation = Location.create(newPath, node.getUuid());
-        request.setActualLocations(oldLocation, newLocation);
-        recordChange(request);
-    }
-
-    @Override
-    public void process( UpdatePropertiesRequest request ) {
-        InMemoryRepository.Workspace workspace = getWorkspace(request, request.inWorkspace());
-        InMemoryNode node = getTargetNode(workspace, request, request.on());
-        if (node == null) return;
-        // Now set (or remove) the properties to the supplied node ...
-        for (Map.Entry<Name, Property> propertyEntry : request.properties().entrySet()) {
-            Property property = propertyEntry.getValue();
-            if (property == null) {
-                node.getProperties().remove(propertyEntry.getKey());
-                continue;
-            }
-            Name propName = property.getName();
-            if (!propName.equals(DnaLexicon.UUID)) {
-                node.getProperties().put(propName, property);
-            }
-        }
-        Location actualLocation = getActualLocation(request.on().getPath(), node);
-        request.setActualLocationOfNode(actualLocation);
-        recordChange(request);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CreateWorkspaceRequest)
-     */
-    @Override
-    public void process( CreateWorkspaceRequest request ) {
-        InMemoryRepository.Workspace workspace = repository.createWorkspace(getExecutionContext(),
-                                                                            request.desiredNameOfNewWorkspace(),
-                                                                            request.conflictBehavior());
-        if (workspace == null) {
-            String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(request.desiredNameOfNewWorkspace(),
-                                                                           repository.getSourceName());
-            request.setError(new InvalidWorkspaceException(msg));
-        } else {
-            InMemoryNode root = workspace.getRoot();
-            request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
-            request.setActualWorkspaceName(workspace.getName());
-            recordChange(request);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DestroyWorkspaceRequest)
-     */
-    @Override
-    public void process( DestroyWorkspaceRequest request ) {
-        InMemoryRepository.Workspace workspace = repository.getWorkspace(getExecutionContext(), request.workspaceName());
-        if (workspace != null) {
-            InMemoryNode root = workspace.getRoot();
-            request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
-            recordChange(request);
-        } else {
-            String msg = GraphI18n.workspaceDoesNotExistInRepository.text(request.workspaceName(), repository.getSourceName());
-            request.setError(new InvalidWorkspaceException(msg));
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.GetWorkspacesRequest)
-     */
-    @Override
-    public void process( GetWorkspacesRequest request ) {
-        Set<String> names = repository.getWorkspaceNames();
-        request.setAvailableWorkspaceNames(new HashSet<String>(names));
-        setCacheableInfo(request);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.VerifyWorkspaceRequest)
-     */
-    @Override
-    public void process( VerifyWorkspaceRequest request ) {
-        InMemoryRepository.Workspace original = getWorkspace(request, request.workspaceName());
-        if (original != null) {
-            Path path = getExecutionContext().getValueFactories().getPathFactory().createRootPath();
-            request.setActualRootLocation(Location.create(path, original.getRoot().getUuid()));
-            request.setActualWorkspaceName(original.getName());
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CloneWorkspaceRequest)
-     */
-    @Override
-    public void process( CloneWorkspaceRequest request ) {
-        // Find the original workspace that we're cloning ...
-        final ExecutionContext context = getExecutionContext();
-        String targetWorkspaceName = request.desiredNameOfTargetWorkspace();
-        String nameOfWorkspaceToBeCloned = request.nameOfWorkspaceToBeCloned();
-        InMemoryRepository.Workspace original = repository.getWorkspace(context, nameOfWorkspaceToBeCloned);
-        InMemoryRepository.Workspace target = repository.getWorkspace(context, targetWorkspaceName);
-        if (original == null) {
-            switch (request.cloneConflictBehavior()) {
-                case DO_NOT_CLONE:
-                    String msg = GraphI18n.workspaceDoesNotExistInRepository.text(nameOfWorkspaceToBeCloned,
-                                                                                  repository.getSourceName());
-                    request.setError(new InvalidWorkspaceException(msg));
-                    return;
-                case SKIP_CLONE:
-                    target = repository.createWorkspace(context, targetWorkspaceName, request.targetConflictBehavior());
-                    if (target == null) {
-                        msg = GraphI18n.workspaceAlreadyExistsInRepository.text(targetWorkspaceName, repository.getSourceName());
-                        request.setError(new InvalidWorkspaceException(msg));
-                    } else {
-                        InMemoryNode root = target.getRoot();
-                        request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
-                        request.setActualWorkspaceName(target.getName());
-                    }
-                    return;
-            }
-        }
-        assert original != null;
-        target = repository.createWorkspace(context,
-                                            targetWorkspaceName,
-                                            request.targetConflictBehavior(),
-                                            nameOfWorkspaceToBeCloned);
-        if (target == null) {
-            // Since the original was there, the only reason the target wasn't created was because the workspace already existed
-            // ...
-            String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(targetWorkspaceName, repository.getSourceName());
-            request.setError(new InvalidWorkspaceException(msg));
-        } else {
-            InMemoryNode root = target.getRoot();
-            request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
-            request.setActualWorkspaceName(target.getName());
-            recordChange(request);
-        }
-    }
-
-    protected Location getActualLocation( Path path,
-                                          InMemoryNode node ) {
-        if (path == null) {
-            // Find the path on the node ...
-            LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
-            InMemoryNode n = node;
-            while (n != null) {
-                if (n.getParent() == null) break;
-                segments.addFirst(n.getName());
-                n = n.getParent();
-            }
-            path = pathFactory.createAbsolutePath(segments);
-        }
-        return Location.create(path, node.getUuid());
-    }
-
-    protected InMemoryRepository.Workspace getWorkspace( Request request,
-                                                         String workspaceName ) {
-        // Get the workspace for this request ...
-        InMemoryRepository.Workspace workspace = repository.getWorkspace(getExecutionContext(), workspaceName);
-        if (workspace == null) {
-            String msg = GraphI18n.workspaceDoesNotExistInRepository.text(workspaceName, repository.getSourceName());
-            request.setError(new InvalidWorkspaceException(msg));
-        }
-        return workspace;
-    }
-
-    protected InMemoryNode getTargetNode( InMemoryRepository.Workspace workspace,
-                                          Request request,
-                                          Location location ) {
-        if (workspace == null) return null;
-        // Check first for the UUID ...
-        InMemoryNode node = null;
-        UUID uuid = location.getUuid();
-        if (uuid != null) {
-            node = workspace.getNode(uuid);
-        }
-        Path path = null;
-        if (node == null) {
-            // Look up the node with the supplied path ...
-            path = location.getPath();
-            if (path != null) {
-                node = workspace.getNode(path);
-            }
-        }
-        if (node == null && request != null) {
-            if (path == null) {
-                if (uuid == null) {
-                    // Missing both path and UUID ...
-                    I18n msg = GraphI18n.inMemoryConnectorRequestsMustHavePathOrUuid;
-                    request.setError(new IllegalArgumentException(msg.text()));
-                    return null;
-                }
-                // Missing path, and could not find by UUID ...
-                request.setError(new PathNotFoundException(location, pathFactory.createRootPath(),
-                                                           GraphI18n.inMemoryNodeDoesNotExist.text(path)));
-                return null;
-            }
-            // Could not find the node given the supplied path, so find the lowest path that does exist ...
-            Path lowestExisting = workspace.getLowestExistingPath(path);
-            request.setError(new PathNotFoundException(location, lowestExisting, GraphI18n.inMemoryNodeDoesNotExist.text(path)));
-        }
-        return node;
-    }
-}

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -0,0 +1,642 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector.map;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.PropertyFactory;
+import org.jboss.dna.graph.property.PropertyType;
+import org.jboss.dna.graph.property.Reference;
+import org.jboss.dna.graph.property.UuidFactory;
+import org.jboss.dna.graph.property.ValueFactory;
+import org.jboss.dna.graph.property.basic.RootPath;
+import org.jboss.dna.graph.request.UuidConflictBehavior;
+
+/**
+ * A default implementation of {@link MapWorkspace} that only requires the user to implement some simple, map-like operations.
+ */
+public abstract class AbstractMapWorkspace implements MapWorkspace {
+
+    private final MapRepository repository;
+    private final String name;
+
+    protected AbstractMapWorkspace( MapRepository repository,
+                                    String name ) {
+        assert repository != null;
+        assert name != null;
+
+        this.repository = repository;
+        this.name = name;
+    }
+
+    protected void initialize() {
+
+        // Create the root node ...
+        MapNode root = createMapNode(repository.getRootNodeUuid());
+        assert root != null;
+        addNodeToMap(root);
+
+    }
+
+    /**
+     * Adds the given node to the backing map, replacing any node already in the backing map with the same UUID.
+     * 
+     * @param node the node to add to the map; may not be null
+     */
+    protected abstract void addNodeToMap( MapNode node );
+
+    /**
+     * Removes the node with the given UUID from the backing map, returning the node if it exists
+     * 
+     * @param nodeUuid the UUID of the node to replace; may not be null
+     * @return if a node with that UUID exists in the backing map (prior to removal), that node is returned; otherwise null
+     */
+    protected abstract MapNode removeNodeFromMap( UUID nodeUuid );
+
+    /**
+     * Removes all of the nodes from the backing map
+     */
+    protected abstract void removeAllNodesFromMap();
+
+    /**
+     * Gets the node with the given UUID from the backing map, if one exists
+     * 
+     * @param nodeUuid the UUID of the node to be retrieved; may not be null
+     * @return the node that exists in the backing map with the given UUID
+     */
+    public abstract MapNode getNode( UUID nodeUuid );
+
+    /**
+     * Creates an empty {@link MapNode node} with the given UUID.
+     * <p>
+     * This method does not add the new map node to the map. That must be done with a separate call to
+     * {@link #addNodeToMap(MapNode)}.
+     * </p>
+     * 
+     * @param uuid the UUID that identifies the new node; may not be null
+     * @return the new node with the given UUID
+     */
+    protected MapNode createMapNode( UUID uuid ) {
+        assert uuid != null;
+        return new MapNode(uuid);
+    }
+
+    /**
+     * @return name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see MapWorkspace#getRoot()
+     */
+    public MapNode getRoot() {
+        return getNode(repository.getRootNodeUuid());
+    }
+
+    /**
+     * Find a node with the given path.
+     * 
+     * @param context the execution context to use to convert {@code path} to a {@link Path}; may not be null
+     * @param path the path to the node; may not be null
+     * @return the node with the path, or null if the node does not exist
+     */
+    public MapNode getNode( ExecutionContext context,
+                            String path ) {
+        assert context != null;
+        assert path != null;
+        return getNode(context.getValueFactories().getPathFactory().create(path));
+    }
+
+    /**
+     * Find a node with the given path.
+     * 
+     * @param path the path to the node; may not be null
+     * @return the node with the path, or null if the node does not exist
+     */
+    public MapNode getNode( Path path ) {
+        assert path != null;
+        MapNode node = getRoot();
+        for (Path.Segment segment : path) {
+            MapNode desiredChild = null;
+            for (MapNode child : node.getChildren()) {
+                if (child == null) continue;
+                Path.Segment childName = child.getName();
+                if (childName == null) continue;
+                if (childName.equals(segment)) {
+                    desiredChild = child;
+                    break;
+                }
+            }
+            if (desiredChild != null) {
+                node = desiredChild;
+            } else {
+                return null;
+            }
+        }
+        return node;
+    }
+
+    /**
+     * Returns the absolute path to the given node
+     * 
+     * @param pathFactory the path factory to use to create the path from the list of names of all of the nodes on the path from
+     *        the root node to the given node
+     * @param node the node for which the path should be returned
+     * @return the absolute path to the given node
+     */
+    public Path pathFor( PathFactory pathFactory,
+                         MapNode node ) {
+        assert node != null;
+        assert pathFactory != null;
+
+        LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
+        MapNode root = getRoot();
+
+        do {
+            segments.addFirst(node.getName());
+            node = node.getParent();
+        } while (!node.equals(root));
+
+        return pathFactory.createAbsolutePath(segments);
+    }
+
+    /**
+     * Find the lowest existing node along the path.
+     * 
+     * @param path the path to the node; may not be null
+     * @return the lowest existing node along the path, or the root node if no node exists on the path
+     */
+    public Path getLowestExistingPath( Path path ) {
+        assert path != null;
+        MapNode node = getRoot();
+        int segmentNumber = 0;
+        for (Path.Segment segment : path) {
+            MapNode desiredChild = null;
+            for (MapNode child : node.getChildren()) {
+                if (child == null) continue;
+                Path.Segment childName = child.getName();
+                if (childName == null) continue;
+                if (childName.equals(segment)) {
+                    desiredChild = child;
+                    break;
+                }
+            }
+            if (desiredChild != null) {
+                node = desiredChild;
+            } else {
+                return path.subpath(0, segmentNumber);
+            }
+            ++segmentNumber;
+        }
+        return RootPath.INSTANCE;
+    }
+
+    /**
+     * Removes the given node and its children, correcting the SNS and child indices for its parent.
+     * 
+     * @param context the current execution context
+     * @param node the node to be removed
+     */
+    public void removeNode( ExecutionContext context,
+                            MapNode node ) {
+        assert context != null;
+        assert node != null;
+        if (getRoot().equals(node)) {
+            removeAllNodesFromMap();
+            // Recreate the root node ...
+            addNodeToMap(createMapNode(repository.getRootNodeUuid()));
+            return;
+        }
+        MapNode parent = node.getParent();
+        assert parent != null;
+        parent.getChildren().remove(node);
+        correctSameNameSiblingIndexes(context, parent, node.getName().getName());
+        removeUuidReference(node);
+    }
+
+    /**
+     * Recursively removes the given node and its children from the backing map
+     * 
+     * @param node the root of the branch to be removed
+     */
+    protected void removeUuidReference( MapNode node ) {
+        assert node != null;
+        removeNodeFromMap(node.getUuid());
+
+        for (MapNode child : node.getChildren()) {
+            removeUuidReference(child);
+        }
+    }
+
+    /**
+     * Create a node at the supplied path. The parent of the new node must already exist.
+     * 
+     * @param context the environment; may not be null
+     * @param pathToNewNode the path to the new node; may not be null
+     * @return the new node (or root if the path specified the root)
+     */
+    public MapNode createNode( ExecutionContext context,
+                               String pathToNewNode ) {
+        assert context != null;
+        assert pathToNewNode != null;
+        Path path = context.getValueFactories().getPathFactory().create(pathToNewNode);
+        if (path.isRoot()) return getRoot();
+        Path parentPath = path.getParent();
+        MapNode parentNode = getNode(parentPath);
+        Name name = path.getLastSegment().getName();
+        return createNode(context, parentNode, name, null);
+    }
+
+    /**
+     * Create a new node with the supplied name, as a child of the supplied parent.
+     * 
+     * @param context the execution context
+     * @param parentNode the parent node; may not be null
+     * @param name the name; may not be null
+     * @param uuid the UUID of the node, or null if the UUID is to be generated
+     * @return the new node
+     */
+    public MapNode createNode( ExecutionContext context,
+                               MapNode parentNode,
+                               Name name,
+                               UUID uuid ) {
+        assert context != null;
+        assert name != null;
+        if (parentNode == null) parentNode = getRoot();
+        if (uuid == null) uuid = UUID.randomUUID();
+
+        MapNode node = createMapNode(uuid);
+        addNodeToMap(node);
+
+        node.setParent(parentNode);
+        // Find the last node with this same name ...
+        int nextIndex = 1;
+        if (parentNode.existingNames.contains(name)) {
+            ListIterator<MapNode> iter = parentNode.getChildren().listIterator(parentNode.getChildren().size());
+            while (iter.hasPrevious()) {
+                MapNode prev = iter.previous();
+                if (prev.getName().getName().equals(name)) {
+                    nextIndex = prev.getName().getIndex() + 1;
+                    break;
+                }
+            }
+        }
+        Path.Segment newName = context.getValueFactories().getPathFactory().createSegment(name, nextIndex);
+        node.setName(newName);
+        parentNode.getChildren().add(node);
+        parentNode.existingNames.add(name);
+        return node;
+    }
+
+    /**
+     * Move the supplied node to the new parent. This method automatically removes the node from its existing parent, and also
+     * correctly adjusts the {@link Path.Segment#getIndex() index} to be correct in the new parent.
+     * 
+     * @param context
+     * @param node the node to be moved; may not be the {@link AbstractMapWorkspace#getRoot() root}
+     * @param desiredNewName the new name for the node, if it is to be changed; may be null
+     * @param newWorkspace the workspace containing the new parent node
+     * @param newParent the new parent; may not be the {@link AbstractMapWorkspace#getRoot() root}
+     * @param beforeNode the node before which this new node should be placed
+     */
+    public void moveNode( ExecutionContext context,
+                          MapNode node,
+                          Name desiredNewName,
+                          MapWorkspace newWorkspace,
+                          MapNode newParent,
+                          MapNode beforeNode ) {
+        assert context != null;
+        assert newParent != null;
+        assert node != null;
+        assert newWorkspace instanceof AbstractMapWorkspace;
+
+        AbstractMapWorkspace newAbstractMapWorkspace = (AbstractMapWorkspace)newWorkspace;
+
+        // Why was this restriction here? -- BRC
+        // assert newAbstractMapWorkspace.getRoot().equals(newParent) != true;
+        assert this.getRoot().equals(node) != true;
+        MapNode oldParent = node.getParent();
+        Name oldName = node.getName().getName();
+        if (oldParent != null) {
+            boolean removed = oldParent.getChildren().remove(node);
+            assert removed == true;
+            node.setParent(null);
+            correctSameNameSiblingIndexes(context, oldParent, oldName);
+        }
+        node.setParent(newParent);
+        Name newName = oldName;
+        if (desiredNewName != null) {
+            newName = desiredNewName;
+            node.setName(context.getValueFactories().getPathFactory().createSegment(desiredNewName, 1));
+        }
+
+        if (beforeNode == null) {
+            newParent.getChildren().add(node);
+        } else {
+            int index = newParent.getChildren().indexOf(beforeNode);
+            newParent.getChildren().add(index, node);
+        }
+        correctSameNameSiblingIndexes(context, newParent, newName);
+
+        // If the node was moved to a new workspace...
+        if (!this.equals(newAbstractMapWorkspace)) {
+            // We need to remove the node from this workspace's map of nodes ...
+            this.moveNodeToWorkspace(node, newAbstractMapWorkspace);
+        }
+    }
+
+    /**
+     * Moves the branch rooted at the given node to the new workspace, removing it from this workspace. If a node with any of the
+     * UUIDs in the branch already exists in the new workspace, it will be replaced by the node from the branch.
+     * 
+     * @param node the root node of the branch to be moved
+     * @param newWorkspace the workspace to which the branch should be moved
+     */
+    protected void moveNodeToWorkspace( MapNode node,
+                                        AbstractMapWorkspace newWorkspace ) {
+        assert getNode(node.getUuid()) != null;
+        assert newWorkspace.getNode(node.getUuid()) == null;
+
+        removeNodeFromMap(node.getUuid());
+        newWorkspace.addNodeToMap(node);
+
+        for (MapNode child : node.getChildren()) {
+            moveNodeToWorkspace(child, newWorkspace);
+        }
+    }
+
+    /**
+     * This should copy the subgraph given by the original node and place the new copy under the supplied new parent. Note that
+     * internal references between nodes within the original subgraph must be reflected as internal nodes within the new subgraph.
+     * 
+     * @param context the context; may not be null
+     * @param original the node to be copied; may not be null
+     * @param newWorkspace the workspace containing the new parent node; may not be null
+     * @param newParent the parent where the copy is to be placed; may not be null
+     * @param desiredName the desired name for the node; if null, the name will be obtained from the original node
+     * @param recursive true if the copy should be recursive
+     * @param uuidConflictBehavior the behavior to use if a UUID in the branch rooted at {@code original} already exists in the
+     *        new workspace
+     * @return the new node, which is the top of the new subgraph
+     */
+    public MapNode copyNode( ExecutionContext context,
+                             MapNode original,
+                             MapWorkspace newWorkspace,
+                             MapNode newParent,
+                             Name desiredName,
+                             boolean recursive,
+                             UuidConflictBehavior uuidConflictBehavior ) throws UuidAlreadyExistsException {
+        Map<UUID, UUID> copyMap = null;
+        Set<UUID> uuidsInFromBranch = null;
+
+        switch (uuidConflictBehavior) {
+            case ALWAYS_CREATE_NEW_UUID:
+
+                /*
+                 * The copyNode method uses the presence of a non-null map as an indicator that new UUIDs should be created
+                 * during the copy operation
+                 */
+                copyMap = new HashMap<UUID, UUID>();
+                break;
+            case REPLACE_EXISTING_NODE:
+                uuidsInFromBranch = getUuidsUnderNode(original);
+
+                for (UUID uuid : uuidsInFromBranch) {
+                    MapNode existing;
+                    if (null != (existing = newWorkspace.getNode(uuid))) {
+                        newWorkspace.removeNode(context, existing);
+                    }
+                }
+                break;
+            case THROW_EXCEPTION:
+                uuidsInFromBranch = getUuidsUnderNode(original);
+                PathFactory pathFactory = context.getValueFactories().getPathFactory();
+                for (UUID uuid : uuidsInFromBranch) {
+                    MapNode existing;
+                    if (null != (existing = newWorkspace.getNode(uuid))) {
+                        NamespaceRegistry namespaces = context.getNamespaceRegistry();
+                        String path = newWorkspace.pathFor(pathFactory, existing).getString(namespaces);
+                        throw new UuidAlreadyExistsException(repository.getSourceName(), uuid, path, newWorkspace.getName());
+                    }
+                }
+                break;
+
+            default:
+                throw new IllegalStateException("Unexpected UUID conflict behavior: " + uuidConflictBehavior);
+        }
+
+        return copyNode(context, original, newWorkspace, newParent, desiredName, true, copyMap);
+    }
+
+    /**
+     * This should copy the subgraph given by the original node and place the new copy under the supplied new parent. Note that
+     * internal references between nodes within the original subgraph must be reflected as internal nodes within the new subgraph.
+     * 
+     * @param context the context; may not be null
+     * @param original the node to be copied; may not be null
+     * @param newWorkspace the workspace containing the new parent node; may not be null
+     * @param newParent the parent where the copy is to be placed; may not be null
+     * @param desiredName the desired name for the node; if null, the name will be obtained from the original node
+     * @param recursive true if the copy should be recursive
+     * @param oldToNewUuids the map of UUIDs of nodes in the new subgraph keyed by the UUIDs of nodes in the original; may be null
+     *        if the UUIDs are to be maintained
+     * @return the new node, which is the top of the new subgraph
+     */
+    protected MapNode copyNode( ExecutionContext context,
+                              MapNode original,
+                              MapWorkspace newWorkspace,
+                              MapNode newParent,
+                              Name desiredName,
+                              boolean recursive,
+                              Map<UUID, UUID> oldToNewUuids ) {
+        assert context != null;
+        assert original != null;
+        assert newParent != null;
+        assert newWorkspace != null;
+        boolean reuseUuids = oldToNewUuids == null;
+
+        // Get or create the new node ...
+        Name childName = desiredName != null ? desiredName : original.getName().getName();
+        UUID uuidForCopy = reuseUuids ? original.getUuid() : UUID.randomUUID();
+        MapNode copy = newWorkspace.createNode(context, newParent, childName, uuidForCopy);
+        if (!reuseUuids) {
+            oldToNewUuids.put(original.getUuid(), copy.getUuid());
+        }
+
+        // Copy the properties ...
+        copy.getProperties().clear();
+        copy.getProperties().putAll(original.getProperties());
+        if (recursive) {
+            // Loop over each child and call this method ...
+            for (MapNode child : original.getChildren()) {
+                copyNode(context, child, newWorkspace, copy, null, true, oldToNewUuids);
+            }
+        }
+
+        if (!reuseUuids) {
+            // Now, adjust any references in the new subgraph to objects in the original subgraph
+            // (because they were internal references, and need to be internal to the new subgraph)
+            PropertyFactory propertyFactory = context.getPropertyFactory();
+            UuidFactory uuidFactory = context.getValueFactories().getUuidFactory();
+            ValueFactory<Reference> referenceFactory = context.getValueFactories().getReferenceFactory();
+            for (Map.Entry<UUID, UUID> oldToNew : oldToNewUuids.entrySet()) {
+                MapNode oldNode = this.getNode(oldToNew.getKey());
+                MapNode newNode = newWorkspace.getNode(oldToNew.getValue());
+                assert oldNode != null;
+                assert newNode != null;
+                // Iterate over the properties of the new ...
+                for (Map.Entry<Name, Property> entry : newNode.getProperties().entrySet()) {
+                    Property property = entry.getValue();
+                    // Now see if any of the property values are references ...
+                    List<Object> newValues = new ArrayList<Object>();
+                    boolean foundReference = false;
+                    for (Iterator<?> iter = property.getValues(); iter.hasNext();) {
+                        Object value = iter.next();
+                        PropertyType type = PropertyType.discoverType(value);
+                        if (type == PropertyType.REFERENCE) {
+                            UUID oldReferencedUuid = uuidFactory.create(value);
+                            UUID newReferencedUuid = oldToNewUuids.get(oldReferencedUuid);
+                            if (newReferencedUuid != null) {
+                                newValues.add(referenceFactory.create(newReferencedUuid));
+                                foundReference = true;
+                            }
+                        } else {
+                            newValues.add(value);
+                        }
+                    }
+                    // If we found at least one reference, we have to build a new Property object ...
+                    if (foundReference) {
+                        Property newProperty = propertyFactory.create(property.getName(), newValues);
+                        entry.setValue(newProperty);
+                    }
+                }
+            }
+        }
+
+        return copy;
+    }
+
+    /**
+     * Returns all of the UUIDs in the branch rooted at {@code node}
+     * 
+     * @param node the root of the branch
+     * @return all of the UUIDs in the branch rooted at {@code node}
+     */
+    public Set<UUID> getUuidsUnderNode( MapNode node ) {
+        Set<UUID> uuids = new HashSet<UUID>();
+        uuidsUnderNode(node, uuids);
+
+        return uuids;
+    }
+
+    private void uuidsUnderNode( MapNode node,
+                                 Set<UUID> accumulator ) {
+        accumulator.add(node.getUuid());
+
+        for (MapNode child : node.getChildren()) {
+            uuidsUnderNode(child, accumulator);
+        }
+    }
+
+    /**
+     * Corrects the SNS indices for all children of the node with the given name
+     * 
+     * @param context the execution context
+     * @param parentNode the parent node
+     * @param name the name of the child nodes for which the SNS indices should be recalculated
+     */
+    protected void correctSameNameSiblingIndexes( ExecutionContext context,
+                                                  MapNode parentNode,
+                                                  Name name ) {
+        if (parentNode == null) return;
+        // Look for the highest existing index ...
+        List<MapNode> childrenWithSameNames = new LinkedList<MapNode>();
+        for (MapNode child : parentNode.getChildren()) {
+            if (child.getName().getName().equals(name)) childrenWithSameNames.add(child);
+        }
+        if (childrenWithSameNames.size() == 0) return;
+        if (childrenWithSameNames.size() == 1) {
+            MapNode childWithSameName = childrenWithSameNames.get(0);
+            Path.Segment newName = context.getValueFactories().getPathFactory().createSegment(name, Path.DEFAULT_INDEX);
+            childWithSameName.setName(newName);
+            return;
+        }
+        int index = 1;
+        for (MapNode childWithSameName : childrenWithSameNames) {
+            Path.Segment segment = childWithSameName.getName();
+            if (segment.getIndex() != index) {
+                Path.Segment newName = context.getValueFactories().getPathFactory().createSegment(name, index);
+                childWithSameName.setName(newName);
+            }
+            ++index;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals( Object obj ) {
+        if (obj == this) return true;
+        if (obj instanceof AbstractMapWorkspace) {
+            AbstractMapWorkspace that = (AbstractMapWorkspace)obj;
+            // Assume the workspaces are in the same repository ...
+            if (!this.name.equals(that.name)) return false;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return repository.getSourceName() + "/" + this.getName();
+    }
+
+}


Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/AbstractMapWorkspace.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapNode.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapNode.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapNode.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -0,0 +1,202 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector.map;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.PropertyFactory;
+
+public class MapNode {
+
+    private final UUID uuid;
+    private MapNode parent;
+    private Path.Segment name;
+    private final Map<Name, Property> properties = new HashMap<Name, Property>();
+    private final LinkedList<MapNode> children = new LinkedList<MapNode>();
+    final Set<Name> existingNames = new HashSet<Name>();
+
+    public MapNode( UUID uuid ) {
+        assert uuid != null;
+        this.uuid = uuid;
+    }
+
+    /* (non-Javadoc)
+     * @see org.jboss.dna.graph.connector.map.MapNode#getUuid()
+     */
+    public UUID getUuid() {
+        return uuid;
+    }
+
+    /* (non-Javadoc)
+     * @see org.jboss.dna.graph.connector.map.MapNode#getName()
+     */
+    public Path.Segment getName() {
+        return name;
+    }
+
+    /**
+     * @param name Sets name to the specified value.
+     */
+    public void setName( Path.Segment name ) {
+        this.name = name;
+    }
+
+    public Set<Name> getUniqueChildNames() {
+        return existingNames;
+    }
+
+    /* (non-Javadoc)
+     * @see org.jboss.dna.graph.connector.map.MapNode#getParent()
+     */
+    public MapNode getParent() {
+        return parent;
+    }
+
+    /**
+     * @param parent Sets parent to the specified value.
+     */
+    public void setParent( MapNode parent ) {
+        this.parent = parent;
+    }
+
+    /**
+     * @return children
+     */
+    public LinkedList<MapNode> getChildren() {
+        return children;
+    }
+
+    /**
+     * @return properties
+     */
+    protected Map<Name, Property> getProperties() {
+        return properties;
+    }
+
+    /**
+     * Sets the property with the given name, overwriting any previous property for the given name
+     * 
+     * @param property the property to set
+     * @return this map node
+     */
+    public MapNode setProperty( Property property ) {
+        if (property != null) {
+            this.properties.put(property.getName(), property);
+        }
+        return this;
+    }
+
+    /**
+     * Sets the property with the given name, overwriting any previous property for the given name
+     * 
+     * @param context the current execution context, used to get a {@link NameFactory name factory} and {@link PropertyFactory
+     *        property factory}.
+     * @param name the name of the property
+     * @param values the values for the property
+     * @return this map node
+     */
+    public MapNode setProperty( ExecutionContext context,
+                                String name,
+                                Object... values ) {
+        PropertyFactory propertyFactory = context.getPropertyFactory();
+        Name propertyName = context.getValueFactories().getNameFactory().create(name);
+        return setProperty(propertyFactory.create(propertyName, values));
+    }
+
+    /**
+     * Returns the named property
+     * 
+     * @param context the current execution context, used to get a {@link NameFactory name factory}
+     * @param name the name of the property to return
+     * @return the property for the given name
+     */
+    public Property getProperty( ExecutionContext context,
+                                 String name ) {
+        Name propertyName = context.getValueFactories().getNameFactory().create(name);
+        return getProperty(propertyName);
+    }
+
+    /**
+     * Returns the named property
+     * 
+     * @param name the name of the property to return
+     * @return the property for the given name
+     */
+    public Property getProperty( Name name ) {
+        return this.properties.get(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return uuid.hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals( Object obj ) {
+        if (obj == this) return true;
+        if (obj instanceof MapNode) {
+            MapNode that = (MapNode)obj;
+            if (!this.getUuid().equals(that.getUuid())) return false;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        if (this.name == null) {
+            sb.append("");
+        } else {
+            sb.append(this.name);
+        }
+        sb.append(" (").append(uuid).append(")");
+        return sb.toString();
+    }
+
+}


Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapNode.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepository.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepository.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepository.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -0,0 +1,271 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector.map;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import net.jcip.annotations.GuardedBy;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.request.UuidConflictBehavior;
+import org.jboss.dna.graph.request.CreateWorkspaceRequest.CreateConflictBehavior;
+
+/**
+ * A default implementation of a map-based repository.
+ * <p>
+ * {@code MapRepository} provides means for creating, retrieving, and destroying {@link MapWorkspace map-based workspaces},
+ * including providing the locking primitives required for safe control of the workspaces.
+ * </p>
+ */
+public abstract class MapRepository {
+
+    protected final ReadWriteLock lock = new ReentrantReadWriteLock();
+    protected final UUID rootNodeUuid;
+    private final String sourceName;
+    private final String defaultWorkspaceName;
+    private final Map<String, MapWorkspace> workspaces = new HashMap<String, MapWorkspace>();
+
+    /**
+     * Creates a {@code MapRepository} with the given repository source name, root node UUID, and a default workspace named
+     * {@code ""} (the empty string).
+     * 
+     * @param sourceName the name of the repository source for use in error and informational messages; may not be null or empty
+     * @param rootNodeUuid the UUID that will be used as the root node UUID for each workspace in the repository; may not be null
+     *        or empty
+     */
+    public MapRepository( String sourceName,
+                          UUID rootNodeUuid ) {
+        this(sourceName, rootNodeUuid, null);
+    }
+
+    /**
+     * Creates a {@code MapRepository} with the given repository source name, root node UUID, and a default workspace with the
+     * given name.
+     * 
+     * @param sourceName the name of the repository source for use in error and informational messages; may not be null or empty
+     * @param rootNodeUuid the UUID that will be used as the root node UUID for each workspace in the repository; may not be null
+     *        or empty
+     * @param defaultWorkspaceName the name of the default, auto-created workspace
+     */
+    public MapRepository( String sourceName,
+                          UUID rootNodeUuid,
+                          String defaultWorkspaceName ) {
+        CheckArg.isNotEmpty(sourceName, "sourceName");
+        CheckArg.isNotNull(rootNodeUuid, "rootNodeUUID");
+        this.rootNodeUuid = rootNodeUuid;
+        this.sourceName = sourceName;
+        this.defaultWorkspaceName = defaultWorkspaceName != null ? defaultWorkspaceName : "";
+    }
+
+    /**
+     * Initializes the repository by creating the default workspace.
+     * <p>
+     * Due to the ordering restrictions on constructor chaining, this method cannot be called until the repository is fully
+     * initialized. <b>This method MUST be called at the end of the constructor by any class that implements {@code MapRepository}
+     * .</b>
+     */
+    protected void initialize() {
+        // Create the default workspace ...
+        workspaces.put(this.defaultWorkspaceName, createWorkspace(null,
+                                                                  this.defaultWorkspaceName,
+                                                                  CreateConflictBehavior.DO_NOT_CREATE));
+
+    }
+
+    /**
+     * Returns the UUID used by the root nodes in each workspace.
+     * <p>
+     * Note that the root nodes themselves are distinct objects in each workspace and a change to the root node of one workspace
+     * does not imply a change to the root nodes of any other workspaces. However, the JCR specification mandates that all
+     * referenceable root nodes in a repository use a common UUID (in support of node correspondence); therefore this must be
+     * supported by DNA.
+     * 
+     * @return the root node UUID
+     */
+    public final UUID getRootNodeUuid() {
+        return rootNodeUuid;
+    }
+
+    /**
+     * Returns the logical name (as opposed to the class name) of the repository source that defined this instance of the
+     * repository for use in error, informational, and other contextual messages.
+     * 
+     * @return sourceName the logical name for the repository source name
+     */
+    public String getSourceName() {
+        return sourceName;
+    }
+
+    /**
+     * Returns the lock that must be used to ensure consistent access to the repository
+     * 
+     * @return lock the lock that must be used to ensure consistent access to the repository
+     */
+    public ReadWriteLock getLock() {
+        return lock;
+    }
+
+    /**
+     * Returns a list of the names of the currently created workspaces
+     * 
+     * @return a list of the names of the currently created workspaces
+     */
+    @GuardedBy( "getLock()" )
+    public Set<String> getWorkspaceNames() {
+        return workspaces.keySet();
+    }
+
+    /**
+     * Returns the workspace with the given name
+     * 
+     * @param name the name of the workspace to return
+     * @return the workspace with the given name; may be null if no workspace with the given name exists
+     */
+    @GuardedBy( "getLock()" )
+    public MapWorkspace getWorkspace( String name ) {
+        if (name == null) name = defaultWorkspaceName;
+        return workspaces.get(name);
+    }
+
+    /**
+     * Creates a new workspace with the given name containing only a root node.
+     * <p>
+     * <b>This method does NOT automatically add the newly created workspace to the {@link #workspaces workspace map} or check to
+     * see if a workspace already exists in this repository with the same name.</b>
+     * </p>
+     * 
+     * @param context the context in which the workspace is to be created
+     * @param name the name of the workspace
+     * @return the newly created workspace; may not be null
+     */
+    @GuardedBy( "getLock()" )
+    protected abstract MapWorkspace createWorkspace( ExecutionContext context,
+                                                     String name );
+
+    /**
+     * Attempts to create a workspace with the given name with name-collision behavior determined by the behavior parameter.
+     * <p>
+     * This method will first check to see if a workspace already exists with the given name. If no such workspace exists, the
+     * method will create a new workspace with the given name, add it to the {@code #workspaces workspaces map}, and return it. If
+     * a workspace with the requested name already exists and the {@code behavior} is {@link CreateConflictBehavior#DO_NOT_CREATE}
+     * , this method will return {@code null} without modifying the state of the repository. If a workspace with the requested
+     * name already exists and the {@code behavior} is {@link CreateConflictBehavior#CREATE_WITH_ADJUSTED_NAME}, this method will
+     * generate a unique new name for the workspace, create a new workspace with the given name, added it to the {@code
+     * #workspaces workspaces map}, and return it.
+     * 
+     * @param context the context in which the workspace is to be created; may not be null
+     * @param name the requested name of the workspace. The name of the workspace that is returned from this method may not be the
+     *        same as the requested name; may not be null
+     * @param behavior the behavior to use in case a workspace with the requested name already exists in the repository
+     * @return the newly created workspace or {@code null} if a workspace with the requested name already exists in the repository
+     *         and {@code behavior == CreateConflictBehavior#DO_NOT_CREATE}.
+     */
+    @GuardedBy( "getLock()" )
+    public MapWorkspace createWorkspace( ExecutionContext context,
+                                         String name,
+                                         CreateConflictBehavior behavior ) {
+        String newName = name;
+        boolean conflictingName = workspaces.containsKey(newName);
+        if (conflictingName) {
+            switch (behavior) {
+                case DO_NOT_CREATE:
+                    return null;
+                case CREATE_WITH_ADJUSTED_NAME:
+                    int counter = 0;
+                    do {
+                        newName = name + (++counter);
+                    } while (workspaces.containsKey(newName));
+                    break;
+            }
+        }
+        assert workspaces.containsKey(newName) == false;
+
+        MapWorkspace workspace = createWorkspace(context, name);
+        workspaces.put(name, workspace);
+        return workspace;
+    }
+
+    /**
+     * Attempts to create a workspace with the requested name as in the
+     * {@link #createWorkspace(ExecutionContext, String, CreateConflictBehavior)} method and then clones the content from the
+     * given source workspace into the new workspace if the creation was successful.
+     * <p>
+     * If no workspace with the name {@code nameOfWorkspaceToClone} exists, the method will return an empty workspace.
+     * </p>
+     * 
+     * @param context the context in which the workspace is to be created; may not be null
+     * @param name the requested name of the workspace. The name of the workspace that is returned from this method may not be the
+     *        same as the requested name; may not be null
+     * @param existingWorkspaceBehavior the behavior to use in case a workspace with the requested name already exists in the
+     *        repository
+     * @param nameOfWorkspaceToClone the name of the workspace from which the content should be cloned; may not be null
+     * @return the newly created workspace with an exact copy of the contents from the workspace named {@code
+     *         nameOfWorkspaceToClone} or {@code null} if a workspace with the requested name already exists in the repository and
+     *         {@code behavior == CreateConflictBehavior#DO_NOT_CREATE}.
+     */
+    @GuardedBy( "getLock()" )
+    public MapWorkspace createWorkspace( ExecutionContext context,
+                                         String name,
+                                         CreateConflictBehavior existingWorkspaceBehavior,
+                                         String nameOfWorkspaceToClone ) {
+        MapWorkspace workspace = createWorkspace(context, name, existingWorkspaceBehavior);
+        if (workspace == null) {
+            // Unable to create because of a duplicate name ...
+            return null;
+        }
+        MapWorkspace original = getWorkspace(nameOfWorkspaceToClone);
+        if (original != null) {
+            // Copy the properties of the root node ...
+            MapNode root = workspace.getRoot();
+            MapNode origRoot = original.getRoot();
+            root.getProperties().clear();
+            root.getProperties().putAll(origRoot.getProperties());
+
+            // Loop over each child and call this method to copy the immediate children (and below).
+            // Note that this makes the copy have the same UUID as the original.
+            for (MapNode originalNode : origRoot.getChildren()) {
+                original.copyNode(context, originalNode, workspace, root, originalNode.getName().getName(), true, UuidConflictBehavior.REPLACE_EXISTING_NODE);
+            }
+        }
+
+        workspaces.put(name, workspace);
+        return workspace;
+    }
+
+    /**
+     * Removes the named workspace from the {@code #workspaces workspaces map}.
+     * 
+     * @param name the name of the workspace to remove
+     * @return {@code true} if a workspace with that name previously existed in the map
+     */
+    @GuardedBy( "getLock()" )
+    public boolean destroyWorkspace( String name ) {
+        return workspaces.remove(name) != null;
+    }
+
+}


Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepository.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositoryConnection.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositoryConnection.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositoryConnection.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -0,0 +1,132 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector.map;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import javax.transaction.xa.XAResource;
+import org.jboss.dna.common.statistic.Stopwatch;
+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.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.request.Request;
+import org.jboss.dna.graph.request.processor.RequestProcessor;
+
+public class MapRepositoryConnection implements RepositoryConnection {
+    private final MapRepositorySource source;
+    private final MapRepository repository;
+
+    public MapRepositoryConnection( MapRepositorySource source,
+                                  MapRepository repository ) {
+        assert source != null;
+        assert repository != null;
+        this.source = source;
+        this.repository = repository;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSourceName() {
+        return source.getName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public CachePolicy getDefaultCachePolicy() {
+        return source.getDefaultCachePolicy();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public XAResource getXAResource() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean ping( long time,
+                         TimeUnit unit ) {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() {
+        // do nothing
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
+     *      org.jboss.dna.graph.request.Request)
+     */
+    public void execute( ExecutionContext context,
+                         Request request ) throws RepositorySourceException {
+        Logger logger = context.getLogger(getClass());
+        Stopwatch sw = null;
+        if (logger.isTraceEnabled()) {
+            sw = new Stopwatch();
+            sw.start();
+        }
+        // Do any commands update/write?
+        RequestProcessor processor = new MapRequestProcessor(context, this.repository, this.source.getRepositoryContext());
+
+        Lock lock = request.isReadOnly() ? repository.getLock().readLock() : repository.getLock().writeLock();
+        lock.lock();
+        try {
+            // Obtain the lock and execute the commands ...
+            processor.process(request);
+        } finally {
+            try {
+                processor.close();
+            } finally {
+                lock.unlock();
+            }
+        }
+        if (logger.isTraceEnabled()) {
+            assert sw != null;
+            sw.stop();
+            logger.trace("MapRepositoryConnection.execute(...) took " + sw.getTotalDuration());
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "Connection to the \"" + getSourceName() + "\" " + repository.getClass().getSimpleName();
+    }
+
+}


Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositoryConnection.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositorySource.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositorySource.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositorySource.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -0,0 +1,48 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector.map;
+
+import org.jboss.dna.graph.cache.CachePolicy;
+import org.jboss.dna.graph.connector.RepositoryContext;
+import org.jboss.dna.graph.connector.RepositorySource;
+
+/**
+ * An extension of the {@link RepositorySource} class that provides a {@link CachePolicy cache policy} and a
+ * {@link RepositoryContext repository context}.
+ */
+public interface MapRepositorySource extends RepositorySource {
+
+    /**
+     * Returns the {@link CachePolicy cache policy} for the repository source 
+     * @return the {@link CachePolicy cache policy} for the repository source
+     */
+    CachePolicy getDefaultCachePolicy();
+
+    /**
+     * Returns the {@link RepositoryContext repository context} for the repository source
+     * @return the {@link RepositoryContext repository context} for the repository source
+     */
+    RepositoryContext getRepositoryContext();
+
+}


Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepositorySource.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -0,0 +1,485 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector.map;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.DnaLexicon;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.JcrLexicon;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.RepositoryContext;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.PathNotFoundException;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.PropertyFactory;
+import org.jboss.dna.graph.property.Path.Segment;
+import org.jboss.dna.graph.request.CloneWorkspaceRequest;
+import org.jboss.dna.graph.request.CopyBranchRequest;
+import org.jboss.dna.graph.request.CreateNodeRequest;
+import org.jboss.dna.graph.request.CreateWorkspaceRequest;
+import org.jboss.dna.graph.request.DeleteBranchRequest;
+import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
+import org.jboss.dna.graph.request.GetWorkspacesRequest;
+import org.jboss.dna.graph.request.InvalidWorkspaceException;
+import org.jboss.dna.graph.request.MoveBranchRequest;
+import org.jboss.dna.graph.request.ReadAllChildrenRequest;
+import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
+import org.jboss.dna.graph.request.Request;
+import org.jboss.dna.graph.request.UpdatePropertiesRequest;
+import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
+import org.jboss.dna.graph.request.processor.RequestProcessor;
+
+/**
+ * The default implementation of the {@link RequestProcessor} for map repositories.
+ *
+ */
+public class MapRequestProcessor extends RequestProcessor {
+    private final PathFactory pathFactory;
+    private final PropertyFactory propertyFactory;
+    private final MapRepository repository;
+
+    public MapRequestProcessor( ExecutionContext context,
+                                   MapRepository repository,
+                                   RepositoryContext repositoryContext ) {
+        super(repository.getSourceName(), context, repositoryContext != null ? repositoryContext.getObserver() : null);
+        this.repository = repository;
+        pathFactory = context.getValueFactories().getPathFactory();
+        propertyFactory = context.getPropertyFactory();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.ReadAllChildrenRequest)
+     */
+    @Override
+    public void process( ReadAllChildrenRequest request ) {
+        MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
+        MapNode node = getTargetNode(workspace, request, request.of());
+        if (node == null) return;
+        Location actualLocation = getActualLocation(request.of().getPath(), node);
+        Path path = actualLocation.getPath();
+        // Get the names of the children ...
+        List<MapNode> children = node.getChildren();
+        for (MapNode child : children) {
+            Segment childName = child.getName();
+            Path childPath = pathFactory.create(path, childName);
+            request.addChild(childPath, propertyFactory.create(DnaLexicon.UUID, child.getUuid()));
+        }
+        request.setActualLocationOfNode(actualLocation);
+        setCacheableInfo(request);
+    }
+
+    @Override
+    public void process( ReadAllPropertiesRequest request ) {
+        MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
+        MapNode node = getTargetNode(workspace, request, request.at());
+        if (node == null) return;
+        // Get the properties of the node ...
+        Location actualLocation = getActualLocation(request.at().getPath(), node);
+        request.addProperty(propertyFactory.create(DnaLexicon.UUID, node.getUuid()));
+        for (Property property : node.getProperties().values()) {
+            request.addProperty(property);
+        }
+        request.setActualLocationOfNode(actualLocation);
+        setCacheableInfo(request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CopyBranchRequest)
+     */
+    @Override
+    public void process( CopyBranchRequest request ) {
+        MapWorkspace workspace = getWorkspace(request, request.fromWorkspace());
+        MapWorkspace newWorkspace = getWorkspace(request, request.intoWorkspace());
+        if (workspace == null || newWorkspace == null) return;
+        MapNode node = getTargetNode(workspace, request, request.from());
+        if (node == null) return;
+
+        // Look up the new parent, which must exist ...
+        Path newParentPath = request.into().getPath();
+        Name desiredName = request.desiredName();
+        MapNode newParent = newWorkspace.getNode(newParentPath);
+        MapNode newNode = workspace.copyNode(getExecutionContext(),
+                                             node,
+                                             newWorkspace,
+                                             newParent,
+                                             desiredName,
+                                             true,
+                                             request.uuidConflictBehavior());
+        Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, newNode.getName());
+        Location oldLocation = getActualLocation(request.from().getPath(), node);
+        Location newLocation = Location.create(newPath, newNode.getUuid());
+        request.setActualLocations(oldLocation, newLocation);
+        recordChange(request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CreateNodeRequest)
+     */
+    @Override
+    public void process( CreateNodeRequest request ) {
+        MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
+        if (workspace == null) return;
+        Path parent = request.under().getPath();
+        CheckArg.isNotNull(parent, "request.under().getPath()");
+        MapNode node = null;
+        // Look up the parent node, which must exist ...
+
+        MapNode parentNode = workspace.getNode(parent);
+        if (parentNode == null) {
+            Path lowestExisting = workspace.getLowestExistingPath(parent);
+            request.setError(new PathNotFoundException(request.under(), lowestExisting,
+                                                       GraphI18n.inMemoryNodeDoesNotExist.text(parent)));
+            return;
+        }
+        UUID uuid = null;
+        for (Property property : request.properties()) {
+            if (property.getName().equals(DnaLexicon.UUID) || property.getName().equals(JcrLexicon.UUID)) {
+                uuid = getExecutionContext().getValueFactories().getUuidFactory().create(property.getValues().next());
+                break;
+            }
+        }
+        switch (request.conflictBehavior()) {
+            case APPEND:
+            case DO_NOT_REPLACE:
+                node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid);
+                break;
+            case REPLACE:
+                // See if the node already exists (this doesn't record an error on the request) ...
+                node = getTargetNode(workspace, null, Location.create(pathFactory.create(parent, request.named()), uuid));
+                if (node != null) {
+                    workspace.removeNode(getExecutionContext(), node);
+                }
+                node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid);
+                break;
+            case UPDATE:
+                // See if the node already exists (this doesn't record an error on the request) ...
+                node = getTargetNode(workspace, null, Location.create(pathFactory.create(parent, request.named()), uuid));
+                if (node == null) {
+                    node = workspace.createNode(getExecutionContext(), parentNode, request.named(), uuid);
+                } // otherwise, we found it and we're setting any properties below
+                break;
+        }
+        assert node != null;
+        Path path = getExecutionContext().getValueFactories().getPathFactory().create(parent, node.getName());
+        // Now add the properties to the supplied node ...
+        for (Property property : request.properties()) {
+            Name propName = property.getName();
+            if (property.size() == 0) {
+                node.getProperties().remove(propName);
+                continue;
+            }
+            if (!propName.equals(DnaLexicon.UUID)) {
+                node.getProperties().put(propName, property);
+            }
+        }
+        Location actualLocation = getActualLocation(path, node);
+        request.setActualLocationOfNode(actualLocation);
+        recordChange(request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DeleteBranchRequest)
+     */
+    @Override
+    public void process( DeleteBranchRequest request ) {
+        MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
+        if (workspace == null) return;
+        MapNode node = getTargetNode(workspace, request, request.at());
+        if (node == null) return;
+        workspace.removeNode(getExecutionContext(), node);
+        Location actualLocation = getActualLocation(request.at().getPath(), node);
+        request.setActualLocationOfNode(actualLocation);
+        recordChange(request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.MoveBranchRequest)
+     */
+    @Override
+    public void process( MoveBranchRequest request ) {
+        MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
+        if (workspace == null) return;
+
+        MapNode beforeNode = request.before() != null ? getTargetNode(workspace, request, request.before()) : null;
+        MapNode node = getTargetNode(workspace, request, request.from());
+        if (node == null) return;
+        // Look up the new parent, which must exist ...
+        Path newParentPath;
+
+        if (request.into() != null) {
+            newParentPath = request.into().getPath();
+        } else {
+            // into or before cannot both be null
+            assert beforeNode != null;
+
+            // Build the path from the before node to the root.
+            LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
+            MapNode current = beforeNode.getParent();
+            while (current != workspace.getRoot()) {
+                segments.addFirst(current.getName());
+                current = current.getParent();
+            }
+            newParentPath = getExecutionContext().getValueFactories().getPathFactory().createAbsolutePath(segments);
+        }
+
+        MapNode newParent = workspace.getNode(newParentPath);
+        workspace.moveNode(getExecutionContext(), node, request.desiredName(), workspace, newParent, beforeNode);
+        assert node.getParent() == newParent;
+        Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName());
+        Location oldLocation = getActualLocation(request.from().getPath(), node);
+        Location newLocation = Location.create(newPath, node.getUuid());
+        request.setActualLocations(oldLocation, newLocation);
+        recordChange(request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.UpdatePropertiesRequest)
+     */
+    @Override
+    public void process( UpdatePropertiesRequest request ) {
+        MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
+        MapNode node = getTargetNode(workspace, request, request.on());
+        if (node == null) return;
+        // Now set (or remove) the properties to the supplied node ...
+        for (Map.Entry<Name, Property> propertyEntry : request.properties().entrySet()) {
+            Property property = propertyEntry.getValue();
+            if (property == null) {
+                node.getProperties().remove(propertyEntry.getKey());
+                continue;
+            }
+            Name propName = property.getName();
+            if (!propName.equals(DnaLexicon.UUID)) {
+                node.getProperties().put(propName, property);
+            }
+        }
+        Location actualLocation = getActualLocation(request.on().getPath(), node);
+        request.setActualLocationOfNode(actualLocation);
+        recordChange(request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CreateWorkspaceRequest)
+     */
+    @Override
+    public void process( CreateWorkspaceRequest request ) {
+        MapWorkspace workspace = repository.createWorkspace(getExecutionContext(),
+                                                            request.desiredNameOfNewWorkspace(),
+                                                            request.conflictBehavior());
+        if (workspace == null) {
+            String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(request.desiredNameOfNewWorkspace(),
+                                                                           repository.getSourceName());
+            request.setError(new InvalidWorkspaceException(msg));
+        } else {
+            MapNode root = workspace.getRoot();
+            request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
+            request.setActualWorkspaceName(workspace.getName());
+            recordChange(request);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DestroyWorkspaceRequest)
+     */
+    @Override
+    public void process( DestroyWorkspaceRequest request ) {
+        MapWorkspace workspace = repository.getWorkspace(request.workspaceName());
+        if (workspace != null) {
+            MapNode root = workspace.getRoot();
+            request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
+            recordChange(request);
+        } else {
+            String msg = GraphI18n.workspaceDoesNotExistInRepository.text(request.workspaceName(), repository.getSourceName());
+            request.setError(new InvalidWorkspaceException(msg));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.GetWorkspacesRequest)
+     */
+    @Override
+    public void process( GetWorkspacesRequest request ) {
+        Set<String> names = repository.getWorkspaceNames();
+        request.setAvailableWorkspaceNames(new HashSet<String>(names));
+        setCacheableInfo(request);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.VerifyWorkspaceRequest)
+     */
+    @Override
+    public void process( VerifyWorkspaceRequest request ) {
+        MapWorkspace original = getWorkspace(request, request.workspaceName());
+        if (original != null) {
+            Path path = getExecutionContext().getValueFactories().getPathFactory().createRootPath();
+            request.setActualRootLocation(Location.create(path, original.getRoot().getUuid()));
+            request.setActualWorkspaceName(original.getName());
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CloneWorkspaceRequest)
+     */
+    @Override
+    public void process( CloneWorkspaceRequest request ) {
+        // Find the original workspace that we're cloning ...
+        final ExecutionContext context = getExecutionContext();
+        String targetWorkspaceName = request.desiredNameOfTargetWorkspace();
+        String nameOfWorkspaceToBeCloned = request.nameOfWorkspaceToBeCloned();
+        MapWorkspace original = repository.getWorkspace(nameOfWorkspaceToBeCloned);
+        MapWorkspace target = repository.getWorkspace(targetWorkspaceName);
+        if (original == null) {
+            switch (request.cloneConflictBehavior()) {
+                case DO_NOT_CLONE:
+                    String msg = GraphI18n.workspaceDoesNotExistInRepository.text(nameOfWorkspaceToBeCloned,
+                                                                                  repository.getSourceName());
+                    request.setError(new InvalidWorkspaceException(msg));
+                    return;
+                case SKIP_CLONE:
+                    target = repository.createWorkspace(context, targetWorkspaceName, request.targetConflictBehavior());
+                    if (target == null) {
+                        msg = GraphI18n.workspaceAlreadyExistsInRepository.text(targetWorkspaceName, repository.getSourceName());
+                        request.setError(new InvalidWorkspaceException(msg));
+                    } else {
+                        MapNode root = target.getRoot();
+                        request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
+                        request.setActualWorkspaceName(target.getName());
+                    }
+                    return;
+            }
+        }
+        assert original != null;
+        target = repository.createWorkspace(context,
+                                            targetWorkspaceName,
+                                            request.targetConflictBehavior(),
+                                            nameOfWorkspaceToBeCloned);
+        if (target == null) {
+            // Since the original was there, the only reason the target wasn't created was because the workspace already existed
+            // ...
+            String msg = GraphI18n.workspaceAlreadyExistsInRepository.text(targetWorkspaceName, repository.getSourceName());
+            request.setError(new InvalidWorkspaceException(msg));
+        } else {
+            MapNode root = target.getRoot();
+            request.setActualRootLocation(Location.create(pathFactory.createRootPath(), root.getUuid()));
+            request.setActualWorkspaceName(target.getName());
+            recordChange(request);
+        }
+    }
+
+    protected Location getActualLocation( Path path,
+                                          MapNode node ) {
+        if (path == null) {
+            // Find the path on the node ...
+            LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
+            MapNode n = node;
+            while (n != null) {
+                if (n.getParent() == null) break;
+                segments.addFirst(n.getName());
+                n = n.getParent();
+            }
+            path = pathFactory.createAbsolutePath(segments);
+        }
+        return Location.create(path, node.getUuid());
+    }
+
+    protected MapWorkspace getWorkspace( Request request,
+                                         String workspaceName ) {
+        // Get the workspace for this request ...
+        MapWorkspace workspace = repository.getWorkspace(workspaceName);
+        if (workspace == null) {
+            String msg = GraphI18n.workspaceDoesNotExistInRepository.text(workspaceName, repository.getSourceName());
+            request.setError(new InvalidWorkspaceException(msg));
+        }
+        return workspace;
+    }
+
+    protected MapNode getTargetNode( MapWorkspace workspace,
+                                     Request request,
+                                     Location location ) {
+        if (workspace == null) return null;
+        // Check first for the UUID ...
+        MapNode node = null;
+        UUID uuid = location.getUuid();
+        if (uuid != null) {
+            node = workspace.getNode(uuid);
+        }
+        Path path = null;
+        if (node == null) {
+            // Look up the node with the supplied path ...
+            path = location.getPath();
+            if (path != null) {
+                node = workspace.getNode(path);
+            }
+        }
+        if (node == null && request != null) {
+            if (path == null) {
+                if (uuid == null) {
+                    // Missing both path and UUID ...
+                    I18n msg = GraphI18n.inMemoryConnectorRequestsMustHavePathOrUuid;
+                    request.setError(new IllegalArgumentException(msg.text()));
+                    return null;
+                }
+                // Missing path, and could not find by UUID ...
+                request.setError(new PathNotFoundException(location, pathFactory.createRootPath(),
+                                                           GraphI18n.inMemoryNodeDoesNotExist.text(path)));
+                return null;
+            }
+            // Could not find the node given the supplied path, so find the lowest path that does exist ...
+            Path lowestExisting = workspace.getLowestExistingPath(path);
+            request.setError(new PathNotFoundException(location, lowestExisting, GraphI18n.inMemoryNodeDoesNotExist.text(path)));
+        }
+        return node;
+    }
+}


Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapWorkspace.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapWorkspace.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapWorkspace.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -0,0 +1,172 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector.map;
+
+import java.util.UUID;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.request.UuidConflictBehavior;
+
+/**
+ * The {@code MapWorkspace} defines the required methods for workspaces in a {@link MapRepository map repository}. By default, a
+ * map repository supports multiple workspaces, each equating logically to a map of UUIDs to {@link MapNode map nodes}.
+ * <p>
+ * As each map node (except the root-node for the workspace) has a non-null parent and a set of children, the {@link MapNode map
+ * nodes} naturally construct a tree within the workspace.
+ * </p>
+ */
+public interface MapWorkspace {
+
+    /**
+     * Returns the name of the workspace. There can only be one workspace with a given name per repository.
+     * 
+     * @return the name of the workspace
+     */
+    String getName();
+
+    /**
+     * Returns the root node in the workspace. This returns a {@link MapNode map node} where {@code node.getParent() == null} and
+     * {@code node.getUuid() == repository.getRootNodeUuid()}.
+     * 
+     * @return the root node in the workspace
+     */
+    MapNode getRoot();
+
+    /**
+     * Returns the node with the given UUID, if one exists or {@code null} if no {@MapNode node} with the given UUID
+     * exists in the workspace.
+     * <p>
+     * That is, {@code node == null || node.getUuid().equals(uuid)} for the returned node.
+     * </p>
+     * 
+     * @param uuid the UUID of the node to be retrieved; may not be null
+     * @return the node with the given UUID, if one exists or {@code null} if no {@MapNode node} with the given UUID
+     *         exists in the workspace.
+     */
+    MapNode getNode( UUID uuid );
+
+    /**
+     * Returns the node at the given path, if one exists of {@code null} if no {@MapNode node} exists at the given path.
+     * 
+     * @param path the path of the node to retrieve; may not be null
+     * @return the node at the given path, if one exists of {@code null} if no {@MapNode node} exists at the given path.
+     */
+    MapNode getNode( Path path );
+
+    /**
+     * Removes the given node. This method will return silently if the given node does not exist in this workspace.
+     * 
+     * @param context the current execution context; may not be null
+     * @param node the node to be removed; may not be null
+     */
+    void removeNode( ExecutionContext context,
+                     MapNode node );
+
+    /**
+     * Create a node at the supplied path. The parent of the new node must already exist.
+     * 
+     * @param context the environment; may not be null
+     * @param pathToNewNode the path to the new node; may not be null
+     * @return the new node (or root if the path specified the root)
+     */
+    MapNode createNode( ExecutionContext context,
+                        String pathToNewNode );
+
+    /**
+     * Create a new node with the supplied name, as a child of the supplied parent.
+     * 
+     * @param context the execution context
+     * @param parentNode the parent node; may not be null
+     * @param name the name; may not be null
+     * @param uuid the UUID of the node, or null if the UUID is to be generated
+     * @return the new node
+     */
+    MapNode createNode( ExecutionContext context,
+                        MapNode parentNode,
+                        Name name,
+                        UUID uuid );
+
+    /**
+     * Move the supplied node to the new parent. This method automatically removes the node from its existing parent, and also
+     * correctly adjusts the {@link Path.Segment#getIndex() index} to be correct in the new parent.
+     * 
+     * @param context
+     * @param node the node to be moved; may not be the {@link MapWorkspace#getRoot() root}
+     * @param desiredNewName the new name for the node, if it is to be changed; may be null
+     * @param newWorkspace the workspace containing the new parent node
+     * @param newParent the new parent; may not be the {@link MapWorkspace#getRoot() root}
+     * @param beforeNode the node before which this new node should be placed
+     */
+    void moveNode( ExecutionContext context,
+                   MapNode node,
+                   Name desiredNewName,
+                   MapWorkspace newWorkspace,
+                   MapNode newParent,
+                   MapNode beforeNode );
+
+    /**
+     * This should copy the subgraph given by the original node and place the new copy under the supplied new parent. Note that
+     * internal references between nodes within the original subgraph must be reflected as internal nodes within the new subgraph.
+     * 
+     * @param context the context; may not be null
+     * @param original the node to be copied; may not be null
+     * @param newWorkspace the workspace containing the new parent node; may not be null
+     * @param newParent the parent where the copy is to be placed; may not be null
+     * @param desiredName the desired name for the node; if null, the name will be obtained from the original node
+     * @param recursive true if the copy should be recursive
+     * @param uuidConflictBehavior the behavior to use to manage UUIDs from the source into the target
+     * @return the new node, which is the top of the new subgraph
+     * @throws UuidAlreadyExistsException if {@code uuidConflictBehavior} is true and and a UUID in the source tree alread exists
+     *         in the new workspace
+     */
+    MapNode copyNode( ExecutionContext context,
+                      MapNode original,
+                      MapWorkspace newWorkspace,
+                      MapNode newParent,
+                      Name desiredName,
+                      boolean recursive,
+                      UuidConflictBehavior uuidConflictBehavior ) throws UuidAlreadyExistsException;
+
+    /**
+     * Find the lowest existing node along the path.
+     * 
+     * @param path the path to the node; may not be null
+     * @return the lowest existing node along the path, or the root node if no node exists on the path
+     */
+    Path getLowestExistingPath( Path path );
+
+    /**
+     * Returns the path for the given node with this workspace if one exists, or a {@code null} if no node exists at the given
+     * path.
+     * 
+     * @param pathFactory the path factory to use to construct the path; may not be null
+     * @param node the node for which the path should be retrieved; may not be null
+     * @return the path for the given node with this workspace if one exists or null if the node does not exist in this workspace
+     */
+    Path pathFor( PathFactory pathFactory,
+                  MapNode node );
+}


Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapWorkspace.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/package-info.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/package-info.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/package-info.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -0,0 +1,72 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors. 
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * The {@link MapRepository} class and its supporting classes provide a default implementation of the connector
+ * classes for connectors that support the transient or persistent mapping of a UUID to a {@link MapNode standard
+ * representation of a node}.
+ * To implement a connector based on this framework, one must create an implementation of {@link MapRepositorySource the repository source},
+ * an implementation of {@link MapRepository the repository itself}, and an implementation of {@link MapWorkspace the workspace}.
+ * <p>
+ * The {@link MapRepositorySource repository source implementation} contains properties for the repository configuration and caching policies.  A key
+ * method in the {@code MapRepositorySource} implementation if the {@link org.jboss.dna.graph.connector.RepositorySource#getConnection()} method,
+ * which should generally be implemented using the {@link MapRepositoryConnection default connection implementation}.
+ * <pre>
+ * if (repository == null) {
+ *  repository = new InMemoryRepository(name, rootNodeUuid, defaultWorkspaceName);
+ * }
+ * return new MapRepositoryConnection(this, repository); 
+ * </pre>
+ * </p>
+ * <p>
+ * The {@link MapRepository repository implementation} is only required to provide an implementation of the {@link MapRepository#createWorkspace(org.jboss.dna.graph.ExecutionContext, String)}
+ * method that returns the appropriate {@link MapWorkspace workspace} implementation for the connector.  However, all constructors for the repository must 
+ * call {@link MapRepository#initialize()} after the constructor has completed its initialization, as demonstrated below:
+ * <pre>
+ * public InMemoryRepository( String sourceName,
+ *                            UUID rootNodeUuid,
+ *                            String defaultWorkspaceName ) {
+ *   initialize();
+ * }
+ * </pre>
+ * </p>
+ * <p>
+ * Finally, the {@link MapWorkspace workspace implementation} must be created.  Implementors should consider extending the {@link AbstractMapWorkspace} class, which provides reasonable default implementations (assuming that the backing map provides O(1) lookups - a sine qua non for maps) for almost
+ * this class imposes a requirement that its {@link AbstractMapWorkspace#initialize()} method also be called at the end of each constructor, like so:
+ * <pre>
+ *  public Workspace( MapRepository repository,
+ *                    String name ) {
+ *      super(repository, name);
+ *
+ *      initialize();
+ *  }
+ * </pre>
+ * </p>
+ * 
+ * @see org.jboss.dna.graph.connector.inmemory.InMemoryRepository
+ * @see org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource
+ * @see org.jboss.dna.graph.connector.inmemory.InMemoryRepository#Workspace
+ */
+
+package org.jboss.dna.graph.connector.map;
+


Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/package-info.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryTest.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryTest.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -31,7 +31,8 @@
 import static org.junit.matchers.JUnitMatchers.hasItems;
 import java.util.UUID;
 import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.connector.inmemory.InMemoryRepository.Workspace;
+import org.jboss.dna.graph.connector.map.MapNode;
+import org.jboss.dna.graph.connector.map.MapWorkspace;
 import org.jboss.dna.graph.property.Name;
 import org.jboss.dna.graph.property.NameFactory;
 import org.jboss.dna.graph.property.PathFactory;
@@ -99,7 +100,7 @@
         String workspaceName = "New Workspace";
         assertThat(repository.createWorkspace(context, workspaceName, CreateConflictBehavior.DO_NOT_CREATE), is(notNullValue()));
         assertThat(repository.getWorkspaceNames(), hasItems(workspaceName));
-        Workspace secondWorkspace = repository.createWorkspace(context,
+        MapWorkspace secondWorkspace = repository.createWorkspace(context,
                                                                workspaceName,
                                                                CreateConflictBehavior.CREATE_WITH_ADJUSTED_NAME);
         assertThat(secondWorkspace, is(notNullValue()));
@@ -124,25 +125,25 @@
     @Test
     public void shouldCloneWorkspaceAndCopyContentsIfWorkspaceWithSpecifiedNameExists() {
         String workspaceName = "Original Workspace";
-        Workspace workspace = repository.createWorkspace(context, workspaceName, CreateConflictBehavior.DO_NOT_CREATE);
+        MapWorkspace workspace = repository.createWorkspace(context, workspaceName, CreateConflictBehavior.DO_NOT_CREATE);
         assertThat(workspace, is(notNullValue()));
         assertThat(repository.getWorkspaceNames(), hasItems(workspaceName));
 
         // Populate the workspace with a few nodes ...
-        InMemoryNode root = workspace.getRoot();
-        InMemoryNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
-        InMemoryNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
-        InMemoryNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
-        InMemoryNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
-        InMemoryNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
-        InMemoryNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
+        MapNode root = workspace.getRoot();
+        MapNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
+        MapNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
+        MapNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
+        MapNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
+        MapNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
+        MapNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
 
         ValueFactory<String> stringFactory = context.getValueFactories().getStringFactory();
         Name propertyName = nameFactory.create("something");
         Property property = propertyFactory.create(propertyName, stringFactory.create("Worth the wait"));
-        node_b.getProperties().put(propertyName, property);
+        node_b.setProperty(property);
 
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(((InMemoryRepository.Workspace) workspace).size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -150,11 +151,11 @@
         assertThat(workspace.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
         assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
         assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
-        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propertyName), is(property));
 
         // Now clone the workspace ...
         String newWorkspaceName = "New Workspace";
-        Workspace new_workspace = repository.createWorkspace(context,
+        MapWorkspace new_workspace = repository.createWorkspace(context,
                                                              newWorkspaceName,
                                                              CreateConflictBehavior.DO_NOT_CREATE,
                                                              workspaceName);
@@ -162,7 +163,7 @@
         assertThat(repository.getWorkspaceNames(), hasItems(workspaceName, newWorkspaceName));
 
         // Now check that the original workspace still has its content ...
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(((InMemoryRepository.Workspace) workspace).size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -170,10 +171,10 @@
         assertThat(workspace.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
         assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
         assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
-        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propertyName), is(property));
 
         // Now check that the new workspace has its content ...
-        assertThat(new_workspace.getNodesByUuid().size(), is(7));
+        assertThat(((InMemoryRepository.Workspace) new_workspace).size(), is(7));
 
         // Since we cloned workspaces, the UUIDs should be the same in each workspace ...
         assertThat(workspace.getNode(pathFactory.create("/")).getUuid(),
@@ -195,25 +196,25 @@
     @Test
     public void shouldCloneWorkspaceButShouldNotCopyContentsIfWorkspaceWithSpecifiedNameDoesNotExist() {
         String workspaceName = "Original Workspace";
-        Workspace workspace = repository.createWorkspace(context, workspaceName, CreateConflictBehavior.DO_NOT_CREATE);
+        MapWorkspace workspace = repository.createWorkspace(context, workspaceName, CreateConflictBehavior.DO_NOT_CREATE);
         assertThat(workspace, is(notNullValue()));
         assertThat(repository.getWorkspaceNames(), hasItems(workspaceName));
 
         // Populate the workspace with a few nodes ...
-        InMemoryNode root = workspace.getRoot();
-        InMemoryNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
-        InMemoryNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
-        InMemoryNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
-        InMemoryNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
-        InMemoryNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
-        InMemoryNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
+        MapNode root = workspace.getRoot();
+        MapNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
+        MapNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
+        MapNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
+        MapNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
+        MapNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
+        MapNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
 
         ValueFactory<String> stringFactory = context.getValueFactories().getStringFactory();
         Name propertyName = nameFactory.create("something");
         Property property = propertyFactory.create(propertyName, stringFactory.create("Worth the wait"));
-        node_b.getProperties().put(propertyName, property);
+        node_b.setProperty(property);
 
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(((InMemoryRepository.Workspace) workspace).size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -221,11 +222,11 @@
         assertThat(workspace.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
         assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
         assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
-        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propertyName), is(property));
 
         // Now clone the workspace ...
         String newWorkspaceName = "New Workspace";
-        Workspace new_workspace = repository.createWorkspace(context,
+        MapWorkspace new_workspace = repository.createWorkspace(context,
                                                              newWorkspaceName,
                                                              CreateConflictBehavior.DO_NOT_CREATE,
                                                              "non-existant workspace");

Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -34,7 +34,7 @@
 import java.util.Map;
 import java.util.UUID;
 import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.connector.inmemory.InMemoryRepository.Workspace;
+import org.jboss.dna.graph.connector.map.MapNode;
 import org.jboss.dna.graph.property.Name;
 import org.jboss.dna.graph.property.NameFactory;
 import org.jboss.dna.graph.property.PathFactory;
@@ -75,7 +75,7 @@
         rootUuid = UUID.randomUUID();
         repository = new InMemoryRepository(repositoryName, rootUuid);
         workspaceName = "My Workspace";
-        workspace = repository.createWorkspace(context, workspaceName, CreateConflictBehavior.DO_NOT_CREATE);
+        workspace = (InMemoryRepository.Workspace) repository.createWorkspace(context, workspaceName, CreateConflictBehavior.DO_NOT_CREATE);
     }
 
     @Test
@@ -97,33 +97,33 @@
     public void shouldAllowRootToBeRemoved() {
         workspace.removeNode(context, workspace.getRoot());
         assertThat(workspace.getRoot().getChildren().size(), is(0));
-        assertThat(workspace.getRoot().getProperties().size(), is(0));
+        // assertThat(workspace.getRoot().getProperties().size(), is(0));
     }
 
     @Test
     public void shouldCreateNodesByPath() {
         Name name_a = nameFactory.create("a");
-        InMemoryNode node_a = workspace.createNode(context, workspace.getRoot(), name_a, null);
+        MapNode node_a = workspace.createNode(context, workspace.getRoot(), name_a, null);
         assertThat(node_a, is(notNullValue()));
         assertThat(node_a.getParent(), is(workspace.getRoot()));
         assertThat(node_a.getName().getName(), is(name_a));
         assertThat(node_a.getName().hasIndex(), is(false));
 
         Name name_b = nameFactory.create("b");
-        InMemoryNode node_b = workspace.createNode(context, node_a, name_b, null);
+        MapNode node_b = workspace.createNode(context, node_a, name_b, null);
         assertThat(node_b, is(notNullValue()));
         assertThat(node_b.getParent(), is(node_a));
         assertThat(node_b.getName().getName(), is(name_b));
         assertThat(node_b.getName().hasIndex(), is(false));
 
         Name name_c = nameFactory.create("c");
-        InMemoryNode node_c = workspace.createNode(context, node_b, name_c, null);
+        MapNode node_c = workspace.createNode(context, node_b, name_c, null);
         assertThat(node_c, is(notNullValue()));
         assertThat(node_c.getParent(), is(node_b));
         assertThat(node_c.getName().getName(), is(name_c));
         assertThat(node_c.getName().hasIndex(), is(false));
 
-        assertThat(workspace.getNodesByUuid().size(), is(4));
+        assertThat(workspace.size(), is(4));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -132,11 +132,11 @@
 
     @Test
     public void shouldNotFindNodesThatDoNotExist() {
-        InMemoryNode node_a = workspace.createNode(context, workspace.getRoot(), nameFactory.create("a"), null);
-        InMemoryNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
+        MapNode node_a = workspace.createNode(context, workspace.getRoot(), nameFactory.create("a"), null);
+        MapNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
         /*Node node_c =*/workspace.createNode(context, node_b, nameFactory.create("c"), null);
 
-        assertThat(workspace.getNodesByUuid().size(), is(4));
+        assertThat(workspace.size(), is(4));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(node_a));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(node_b));
         assertThat(workspace.getNode(pathFactory.create("/a[1]")), is(node_a));
@@ -150,50 +150,50 @@
     @Test
     public void shouldCorrectlyManageIndexesOfSiblingsWithSameNames() {
         Name name_a1 = nameFactory.create("a");
-        InMemoryNode node_a1 = workspace.createNode(context, workspace.getRoot(), name_a1, null);
+        MapNode node_a1 = workspace.createNode(context, workspace.getRoot(), name_a1, null);
         assertThat(node_a1, is(notNullValue()));
         assertThat(node_a1.getParent(), is(workspace.getRoot()));
         assertThat(node_a1.getName().getName(), is(name_a1));
         assertThat(node_a1.getName().hasIndex(), is(false));
 
         Name name_a2 = nameFactory.create("a");
-        InMemoryNode node_a2 = workspace.createNode(context, workspace.getRoot(), name_a2, null);
+        MapNode node_a2 = workspace.createNode(context, workspace.getRoot(), name_a2, null);
         assertThat(node_a2, is(notNullValue()));
         assertThat(node_a2.getParent(), is(workspace.getRoot()));
         assertThat(node_a2.getName().getName(), is(name_a2));
         assertThat(node_a2.getName().hasIndex(), is(true));
         assertThat(node_a2.getName().getIndex(), is(2));
 
-        // node 1 should now have an index ...
+        // node 1 should now have an index ..
         assertThat(node_a1.getName().getIndex(), is(1));
 
-        // Add another node without the same name ...
+        // Add another node without the same name ..
         Name name_b = nameFactory.create("b");
-        InMemoryNode node_b = workspace.createNode(context, workspace.getRoot(), name_b, null);
+        MapNode node_b = workspace.createNode(context, workspace.getRoot(), name_b, null);
         assertThat(node_b, is(notNullValue()));
         assertThat(node_b.getParent(), is(workspace.getRoot()));
         assertThat(node_b.getName().getName(), is(name_b));
         assertThat(node_b.getName().hasIndex(), is(false));
 
-        // Add a third node with the same name ...
+        // Add a third node with the same name ..
         Name name_a3 = nameFactory.create("a");
-        InMemoryNode node_a3 = workspace.createNode(context, workspace.getRoot(), name_a3, null);
+        MapNode node_a3 = workspace.createNode(context, workspace.getRoot(), name_a3, null);
         assertThat(node_a3, is(notNullValue()));
         assertThat(node_a3.getParent(), is(workspace.getRoot()));
         assertThat(node_a3.getName().getName(), is(name_a3));
         assertThat(node_a3.getName().hasIndex(), is(true));
         assertThat(node_a3.getName().getIndex(), is(3));
 
-        // Check the number of children ...
+        // Check the number of children ..
         assertThat(workspace.getRoot().getChildren().size(), is(4));
         assertThat(workspace.getRoot().getChildren(), hasItems(node_a1, node_a2, node_b, node_a3));
-        assertThat(workspace.getNodesByUuid().size(), is(5));
+        assertThat(workspace.size(), is(5));
         assertThat(workspace.getNode(pathFactory.create("/a[1]")), is(sameInstance(node_a1)));
         assertThat(workspace.getNode(pathFactory.create("/a[2]")), is(sameInstance(node_a2)));
         assertThat(workspace.getNode(pathFactory.create("/a[3]")), is(sameInstance(node_a3)));
         assertThat(workspace.getNode(pathFactory.create("/b")), is(sameInstance(node_b)));
 
-        // Removing a node with the same name will reduce the index ...
+        // Removing a node with the same name will reduce the index ..
         workspace.removeNode(context, node_a2);
         assertThat(workspace.getRoot().getChildren().size(), is(3));
         assertThat(workspace.getRoot().getChildren(), hasItems(node_a1, node_b, node_a3));
@@ -201,26 +201,26 @@
         assertThat(node_b.getName().hasIndex(), is(false));
         assertThat(node_a3.getName().getIndex(), is(2));
 
-        // Removing a node with the same name will reduce the index ...
+        // Removing a node with the same name will reduce the index ..
         workspace.removeNode(context, node_a1);
         assertThat(workspace.getRoot().getChildren().size(), is(2));
         assertThat(workspace.getRoot().getChildren(), hasItems(node_b, node_a3));
         assertThat(node_b.getName().hasIndex(), is(false));
         assertThat(node_a3.getName().hasIndex(), is(false));
-        assertThat(workspace.getNodesByUuid().size(), is(3));
+        assertThat(workspace.size(), is(3));
     }
 
     @Test
     public void shouldMoveNodesWithinSameWorkspace() {
-        InMemoryNode root = workspace.getRoot();
-        InMemoryNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
-        InMemoryNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
-        InMemoryNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
-        InMemoryNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
-        InMemoryNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
-        InMemoryNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
+        MapNode root = workspace.getRoot();
+        MapNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
+        MapNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
+        MapNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
+        MapNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
+        MapNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
+        MapNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
 
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(workspace.size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -252,18 +252,18 @@
 
     @Test
     public void shouldMoveNodeBeforeAnother() {
-        InMemoryNode root = workspace.getRoot();
-        InMemoryNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
-        InMemoryNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
-        InMemoryNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
-        InMemoryNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
-        InMemoryNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
-        InMemoryNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
+        MapNode root = workspace.getRoot();
+        MapNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
+        MapNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
+        MapNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
+        MapNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
+        MapNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
+        MapNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
         Name propName = nameFactory.create("prop");
         node_b.setProperty(propertyFactory.create(propName, "node_b"));
         node_b2.setProperty(propertyFactory.create(propName, "node_b2"));
 
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(workspace.size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -303,16 +303,16 @@
 
     @Test
     public void shouldMoveNodesFromOneWorkspaceToAnother() {
-        // Populate the workspace with some content ...
-        InMemoryNode root = workspace.getRoot();
-        InMemoryNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
-        InMemoryNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
-        InMemoryNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
-        InMemoryNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
-        InMemoryNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
-        InMemoryNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
+        // Populate the workspace with some content ..
+        MapNode root = workspace.getRoot();
+        MapNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
+        MapNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
+        MapNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
+        MapNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
+        MapNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
+        MapNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
 
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(workspace.size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -321,19 +321,19 @@
         assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
         assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
 
-        // Create the second workspace and populate it with some content ...
-        Workspace new_workspace = repository.createWorkspace(context, "Second Workspace", CreateConflictBehavior.DO_NOT_CREATE);
+        // Create the second workspace and populate it with some content ..
+        InMemoryRepository.Workspace new_workspace = (InMemoryRepository.Workspace) repository.createWorkspace(context, "Second Workspace", CreateConflictBehavior.DO_NOT_CREATE);
         assertThat(new_workspace, is(notNullValue()));
 
-        InMemoryNode new_root = new_workspace.getRoot();
-        InMemoryNode new_node_a = new_workspace.createNode(context, new_root, nameFactory.create("a"), null);
-        InMemoryNode new_node_b = new_workspace.createNode(context, new_node_a, nameFactory.create("b"), null);
-        InMemoryNode new_node_c = new_workspace.createNode(context, new_node_b, nameFactory.create("c"), null);
-        InMemoryNode new_node_d = new_workspace.createNode(context, new_root, nameFactory.create("d"), null);
-        InMemoryNode new_node_e = new_workspace.createNode(context, new_node_d, nameFactory.create("e"), null);
-        InMemoryNode new_node_b2 = new_workspace.createNode(context, new_node_d, nameFactory.create("b"), null);
+        MapNode new_root = new_workspace.getRoot();
+        MapNode new_node_a = new_workspace.createNode(context, new_root, nameFactory.create("a"), null);
+        MapNode new_node_b = new_workspace.createNode(context, new_node_a, nameFactory.create("b"), null);
+        MapNode new_node_c = new_workspace.createNode(context, new_node_b, nameFactory.create("c"), null);
+        MapNode new_node_d = new_workspace.createNode(context, new_root, nameFactory.create("d"), null);
+        MapNode new_node_e = new_workspace.createNode(context, new_node_d, nameFactory.create("e"), null);
+        MapNode new_node_b2 = new_workspace.createNode(context, new_node_d, nameFactory.create("b"), null);
 
-        assertThat(new_workspace.getNodesByUuid().size(), is(7));
+        assertThat(new_workspace.size(), is(7));
         assertThat(new_workspace.getNode(pathFactory.create("/")), is(sameInstance(new_root)));
         assertThat(new_workspace.getNode(pathFactory.create("/a")), is(sameInstance(new_node_a)));
         assertThat(new_workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(new_node_b)));
@@ -345,14 +345,14 @@
         // Move 'workspace::/a/b' into 'newWorkspace::/d'
         workspace.moveNode(context, node_b, null, new_workspace, new_node_d, null);
 
-        assertThat(workspace.getNodesByUuid().size(), is(5));
+        assertThat(workspace.size(), is(5));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
         assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
         assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
 
-        assertThat(new_workspace.getNodesByUuid().size(), is(9));
+        assertThat(new_workspace.size(), is(9));
         assertThat(new_workspace.getNode(pathFactory.create("/")), is(sameInstance(new_root)));
         assertThat(new_workspace.getNode(pathFactory.create("/a")), is(sameInstance(new_node_a)));
         assertThat(new_workspace.getNode(pathFactory.create("/d")), is(sameInstance(new_node_d)));
@@ -364,20 +364,20 @@
 
     @Test
     public void shouldCopyNodesWithinSameWorkspace() {
-        InMemoryNode root = workspace.getRoot();
-        InMemoryNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
-        InMemoryNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
-        InMemoryNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
-        InMemoryNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
-        InMemoryNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
-        InMemoryNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
+        MapNode root = workspace.getRoot();
+        MapNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
+        MapNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
+        MapNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
+        MapNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
+        MapNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
+        MapNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
 
         ValueFactory<String> stringFactory = valueFactories.getStringFactory();
         Name propertyName = nameFactory.create("something");
         Property property = propertyFactory.create(propertyName, stringFactory.create("Worth the wait"));
-        node_b.getProperties().put(propertyName, property);
+        node_b.setProperty(property);
 
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(workspace.size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -386,11 +386,11 @@
         assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
         assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
 
-        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propertyName), is(property));
 
         workspace.copyNode(context, node_b, workspace, node_d, null, true, new HashMap<UUID, UUID>());
 
-        assertThat(workspace.getNodesByUuid().size(), is(9));
+        assertThat(workspace.size(), is(9));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -401,27 +401,27 @@
         assertThat(workspace.getNode(pathFactory.create("/d/b[2]")), is(notNullValue()));
         assertThat(workspace.getNode(pathFactory.create("/d/b[2]/c")), is(notNullValue()));
 
-        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
-        assertThat(workspace.getNode(pathFactory.create("/d/b[2]")).getProperties().get(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/d/b[2]")).getProperty(propertyName), is(property));
     }
 
     @Test
     public void shouldCopyNodesFromOneWorkspaceToAnotherAndKeepSameUuids() {
-        // Populate the workspace with some content ...
-        InMemoryNode root = workspace.getRoot();
-        InMemoryNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
-        InMemoryNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
-        InMemoryNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
-        InMemoryNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
-        InMemoryNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
-        InMemoryNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
+        // Populate the workspace with some content ..
+        MapNode root = workspace.getRoot();
+        MapNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
+        MapNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
+        MapNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
+        MapNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
+        MapNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
+        MapNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
 
         ValueFactory<String> stringFactory = valueFactories.getStringFactory();
         Name propertyName = nameFactory.create("something");
         Property property = propertyFactory.create(propertyName, stringFactory.create("Worth the wait"));
-        node_b.getProperties().put(propertyName, property);
+        node_b.setProperty(property);
 
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(workspace.size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -430,21 +430,21 @@
         assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
         assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
 
-        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propertyName), is(property));
 
-        // Create the second workspace and populate it with some content ...
-        Workspace new_workspace = repository.createWorkspace(context, "Second Workspace", CreateConflictBehavior.DO_NOT_CREATE);
+        // Create the second workspace and populate it with some content ..
+        InMemoryRepository.Workspace new_workspace = (InMemoryRepository.Workspace) repository.createWorkspace(context, "Second Workspace", CreateConflictBehavior.DO_NOT_CREATE);
         assertThat(new_workspace, is(notNullValue()));
 
-        InMemoryNode new_root = new_workspace.getRoot();
-        InMemoryNode new_node_a = new_workspace.createNode(context, new_root, nameFactory.create("a"), null);
-        InMemoryNode new_node_b = new_workspace.createNode(context, new_node_a, nameFactory.create("b"), null);
-        InMemoryNode new_node_c = new_workspace.createNode(context, new_node_b, nameFactory.create("c"), null);
-        InMemoryNode new_node_d = new_workspace.createNode(context, new_root, nameFactory.create("d"), null);
-        InMemoryNode new_node_e = new_workspace.createNode(context, new_node_d, nameFactory.create("e"), null);
-        InMemoryNode new_node_b2 = new_workspace.createNode(context, new_node_d, nameFactory.create("b"), null);
+        MapNode new_root = new_workspace.getRoot();
+        MapNode new_node_a = new_workspace.createNode(context, new_root, nameFactory.create("a"), null);
+        MapNode new_node_b = new_workspace.createNode(context, new_node_a, nameFactory.create("b"), null);
+        MapNode new_node_c = new_workspace.createNode(context, new_node_b, nameFactory.create("c"), null);
+        MapNode new_node_d = new_workspace.createNode(context, new_root, nameFactory.create("d"), null);
+        MapNode new_node_e = new_workspace.createNode(context, new_node_d, nameFactory.create("e"), null);
+        MapNode new_node_b2 = new_workspace.createNode(context, new_node_d, nameFactory.create("b"), null);
 
-        assertThat(new_workspace.getNodesByUuid().size(), is(7));
+        assertThat(new_workspace.size(), is(7));
         assertThat(new_workspace.getNode(pathFactory.create("/")), is(sameInstance(new_root)));
         assertThat(new_workspace.getNode(pathFactory.create("/a")), is(sameInstance(new_node_a)));
         assertThat(new_workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(new_node_b)));
@@ -454,9 +454,9 @@
         assertThat(new_workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(new_node_b2)));
 
         // Copy 'workspace::/a/b' into 'newWorkspace::/d'
-        workspace.copyNode(context, node_b, new_workspace, new_node_d, null, true, null);
+        workspace.copyNode(context, node_b, new_workspace, new_node_d, null, true, (Map<UUID, UUID>) null);
 
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(workspace.size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -464,9 +464,9 @@
         assertThat(workspace.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
         assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
         assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
-        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propertyName), is(property));
 
-        assertThat(new_workspace.getNodesByUuid().size(), is(9));
+        assertThat(new_workspace.size(), is(9));
         assertThat(new_workspace.getNode(pathFactory.create("/")), is(sameInstance(new_root)));
         assertThat(new_workspace.getNode(pathFactory.create("/a")), is(sameInstance(new_node_a)));
         assertThat(new_workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(new_node_b)));
@@ -477,11 +477,11 @@
         assertThat(new_workspace.getNode(pathFactory.create("/d/b[2]")), is(notNullValue()));
         assertThat(new_workspace.getNode(pathFactory.create("/d/b[2]/c")), is(notNullValue()));
 
-        assertThat(new_workspace.getNode(pathFactory.create("/d/b[2]")).getProperties().get(propertyName), is(property));
+        assertThat(new_workspace.getNode(pathFactory.create("/d/b[2]")).getProperty(propertyName), is(property));
 
-        // The new copy should have the same UUIDs as in the original, since we specified no UUID map ...
-        InMemoryNode new_copy_b = new_workspace.getNode(pathFactory.create("/d/b[2]"));
-        InMemoryNode new_copy_c = new_workspace.getNode(pathFactory.create("/d/b[2]/c"));
+        // The new copy should have the same UUIDs as in the original, since we specified no UUID map ..
+        MapNode new_copy_b = new_workspace.getNode(pathFactory.create("/d/b[2]"));
+        MapNode new_copy_c = new_workspace.getNode(pathFactory.create("/d/b[2]/c"));
         assertThat(new_copy_b, is(notNullValue()));
         assertThat(new_copy_c, is(notNullValue()));
         assertThat(new_copy_b.getUuid(), is(node_b.getUuid()));
@@ -490,21 +490,21 @@
 
     @Test
     public void shouldCopyNodesFromOneWorkspaceToAnotherAndGenerateNewUuids() {
-        // Populate the workspace with some content ...
-        InMemoryNode root = workspace.getRoot();
-        InMemoryNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
-        InMemoryNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
-        InMemoryNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
-        InMemoryNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
-        InMemoryNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
-        InMemoryNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
+        // Populate the workspace with some content ..
+        MapNode root = workspace.getRoot();
+        MapNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
+        MapNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
+        MapNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
+        MapNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
+        MapNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
+        MapNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
 
         ValueFactory<String> stringFactory = valueFactories.getStringFactory();
         Name propertyName = nameFactory.create("something");
         Property property = propertyFactory.create(propertyName, stringFactory.create("Worth the wait"));
-        node_b.getProperties().put(propertyName, property);
+        node_b.setProperty(property);
 
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(workspace.size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -513,21 +513,21 @@
         assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
         assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
 
-        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propertyName), is(property));
 
-        // Create the second workspace and populate it with some content ...
-        Workspace new_workspace = repository.createWorkspace(context, "Second Workspace", CreateConflictBehavior.DO_NOT_CREATE);
+        // Create the second workspace and populate it with some content ..
+        InMemoryRepository.Workspace new_workspace = (InMemoryRepository.Workspace) repository.createWorkspace(context, "Second Workspace", CreateConflictBehavior.DO_NOT_CREATE);
         assertThat(new_workspace, is(notNullValue()));
 
-        InMemoryNode new_root = new_workspace.getRoot();
-        InMemoryNode new_node_a = new_workspace.createNode(context, new_root, nameFactory.create("a"), null);
-        InMemoryNode new_node_b = new_workspace.createNode(context, new_node_a, nameFactory.create("b"), null);
-        InMemoryNode new_node_c = new_workspace.createNode(context, new_node_b, nameFactory.create("c"), null);
-        InMemoryNode new_node_d = new_workspace.createNode(context, new_root, nameFactory.create("d"), null);
-        InMemoryNode new_node_e = new_workspace.createNode(context, new_node_d, nameFactory.create("e"), null);
-        InMemoryNode new_node_b2 = new_workspace.createNode(context, new_node_d, nameFactory.create("b"), null);
+        MapNode new_root = new_workspace.getRoot();
+        MapNode new_node_a = new_workspace.createNode(context, new_root, nameFactory.create("a"), null);
+        MapNode new_node_b = new_workspace.createNode(context, new_node_a, nameFactory.create("b"), null);
+        MapNode new_node_c = new_workspace.createNode(context, new_node_b, nameFactory.create("c"), null);
+        MapNode new_node_d = new_workspace.createNode(context, new_root, nameFactory.create("d"), null);
+        MapNode new_node_e = new_workspace.createNode(context, new_node_d, nameFactory.create("e"), null);
+        MapNode new_node_b2 = new_workspace.createNode(context, new_node_d, nameFactory.create("b"), null);
 
-        assertThat(new_workspace.getNodesByUuid().size(), is(7));
+        assertThat(new_workspace.size(), is(7));
         assertThat(new_workspace.getNode(pathFactory.create("/")), is(sameInstance(new_root)));
         assertThat(new_workspace.getNode(pathFactory.create("/a")), is(sameInstance(new_node_a)));
         assertThat(new_workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(new_node_b)));
@@ -540,7 +540,7 @@
         Map<UUID, UUID> oldToNewUuids = new HashMap<UUID, UUID>();
         workspace.copyNode(context, node_b, new_workspace, new_node_d, null, true, oldToNewUuids);
 
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(workspace.size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -549,9 +549,9 @@
         assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
         assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
 
-        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propertyName), is(property));
 
-        assertThat(new_workspace.getNodesByUuid().size(), is(9));
+        assertThat(new_workspace.size(), is(9));
         assertThat(new_workspace.getNode(pathFactory.create("/")), is(sameInstance(new_root)));
         assertThat(new_workspace.getNode(pathFactory.create("/a")), is(sameInstance(new_node_a)));
         assertThat(new_workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(new_node_b)));
@@ -562,11 +562,11 @@
         assertThat(new_workspace.getNode(pathFactory.create("/d/b[2]")), is(notNullValue()));
         assertThat(new_workspace.getNode(pathFactory.create("/d/b[2]/c")), is(notNullValue()));
 
-        assertThat(new_workspace.getNode(pathFactory.create("/d/b[2]")).getProperties().get(propertyName), is(property));
+        assertThat(new_workspace.getNode(pathFactory.create("/d/b[2]")).getProperty(propertyName), is(property));
 
-        // The new copy should have different UUIDs than in the original, since we did specify a UUID map ...
-        InMemoryNode new_copy_b = new_workspace.getNode(pathFactory.create("/d/b[2]"));
-        InMemoryNode new_copy_c = new_workspace.getNode(pathFactory.create("/d/b[2]/c"));
+        // The new copy should have different UUIDs than in the original, since we did specify a UUID map ..
+        MapNode new_copy_b = new_workspace.getNode(pathFactory.create("/d/b[2]"));
+        MapNode new_copy_c = new_workspace.getNode(pathFactory.create("/d/b[2]/c"));
         assertThat(new_copy_b, is(notNullValue()));
         assertThat(new_copy_c, is(notNullValue()));
         assertThat(new_copy_b.getUuid(), is(not(node_b.getUuid())));
@@ -577,20 +577,20 @@
 
     @Test
     public void shouldCopyNodesWhenDesiredNameIsSpecified() {
-        InMemoryNode root = workspace.getRoot();
-        InMemoryNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
-        InMemoryNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
-        InMemoryNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
-        InMemoryNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
-        InMemoryNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
-        InMemoryNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
+        MapNode root = workspace.getRoot();
+        MapNode node_a = workspace.createNode(context, root, nameFactory.create("a"), null);
+        MapNode node_b = workspace.createNode(context, node_a, nameFactory.create("b"), null);
+        MapNode node_c = workspace.createNode(context, node_b, nameFactory.create("c"), null);
+        MapNode node_d = workspace.createNode(context, root, nameFactory.create("d"), null);
+        MapNode node_e = workspace.createNode(context, node_d, nameFactory.create("e"), null);
+        MapNode node_b2 = workspace.createNode(context, node_d, nameFactory.create("b"), null);
 
         ValueFactory<String> stringFactory = valueFactories.getStringFactory();
         Name propertyName = nameFactory.create("something");
         Property property = propertyFactory.create(propertyName, stringFactory.create("Worth the wait"));
-        node_b.getProperties().put(propertyName, property);
+        node_b.setProperty(property);
 
-        assertThat(workspace.getNodesByUuid().size(), is(7));
+        assertThat(workspace.size(), is(7));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -599,11 +599,11 @@
         assertThat(workspace.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
         assertThat(workspace.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
 
-        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propertyName), is(property));
 
         workspace.copyNode(context, node_b, workspace, node_d, nameFactory.create("x"), true, new HashMap<UUID, UUID>());
 
-        assertThat(workspace.getNodesByUuid().size(), is(9));
+        assertThat(workspace.size(), is(9));
         assertThat(workspace.getNode(pathFactory.create("/")), is(sameInstance(workspace.getRoot())));
         assertThat(workspace.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
         assertThat(workspace.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
@@ -614,8 +614,8 @@
         assertThat(workspace.getNode(pathFactory.create("/d/x")), is(notNullValue()));
         assertThat(workspace.getNode(pathFactory.create("/d/x/c")), is(notNullValue()));
 
-        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
-        assertThat(workspace.getNode(pathFactory.create("/d/x")).getProperties().get(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propertyName), is(property));
+        assertThat(workspace.getNode(pathFactory.create("/d/x")).getProperty(propertyName), is(property));
     }
 
     @Test

Deleted: 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	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheConnection.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -1,108 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of 
- * individual contributors. 
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.connector.jbosscache;
-
-import java.util.concurrent.TimeUnit;
-import javax.transaction.xa.XAResource;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.cache.CachePolicy;
-import org.jboss.dna.graph.connector.RepositoryConnection;
-import org.jboss.dna.graph.connector.RepositorySourceException;
-import org.jboss.dna.graph.observe.Observer;
-import org.jboss.dna.graph.request.Request;
-import org.jboss.dna.graph.request.processor.RequestProcessor;
-
-/**
- * The repository connection to a JBoss Cache instance.
- * 
- * @author Randall Hauch
- */
-public class JBossCacheConnection implements RepositoryConnection {
-
-    private final JBossCacheSource source;
-    private final JBossCacheWorkspaces workspaces;
-
-    JBossCacheConnection( JBossCacheSource source,
-                          JBossCacheWorkspaces workspaces ) {
-        assert source != null;
-        assert workspaces != null;
-        this.source = source;
-        this.workspaces = workspaces;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String getSourceName() {
-        return source.getName();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public CachePolicy getDefaultCachePolicy() {
-        return source.getDefaultCachePolicy();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public XAResource getXAResource() {
-        return null;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean ping( long time,
-                         TimeUnit unit ) {
-        return true;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public void close() {
-        // do nothing
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.connector.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
-     *      org.jboss.dna.graph.request.Request)
-     */
-    public void execute( final ExecutionContext context,
-                         final Request request ) throws RepositorySourceException {
-        Observer observer = source.getObserver();
-        RequestProcessor processor = new JBossCacheRequestProcessor(getSourceName(), context, observer, workspaces,
-                                                                    source.getNameOfDefaultWorkspace(),
-                                                                    source.isCreatingWorkspacesAllowed());
-        try {
-            processor.process(request);
-        } finally {
-            processor.close();
-        }
-    }
-}

Deleted: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheLexicon.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheLexicon.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheLexicon.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -1,45 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of 
- * individual contributors. 
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.connector.jbosscache;
-
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.basic.BasicName;
-
-/**
- * The namespace and property names used within a {@link JBossCacheSource} to store internal information.
- * 
- * @author Randall Hauch
- */
-public class JBossCacheLexicon {
-
-    public static class Namespace {
-        public static final String URI = "http://www.jboss.org/dna/connector/jbosscache";
-        public static final String PREFIX = "dnajbcc";
-    }
-
-    public static final Name CHILD_PATH_SEGMENT_LIST = new BasicName(Namespace.URI, "orderedChildNames");
-    public static final Name UUIDS = new BasicName(Namespace.URI, "uuids");
-    public static final Name FQN = new BasicName(Namespace.URI, "fqn");
-
-}

Added: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java	                        (rev 0)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -0,0 +1,79 @@
+package org.jboss.dna.connector.jbosscache;
+
+import java.util.UUID;
+import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.map.AbstractMapWorkspace;
+import org.jboss.dna.graph.connector.map.MapNode;
+import org.jboss.dna.graph.connector.map.MapRepository;
+import org.jboss.dna.graph.connector.map.MapWorkspace;
+
+public class JBossCacheRepository extends MapRepository {
+
+    private final Cache<UUID, MapNode> cache;
+
+    public JBossCacheRepository( String sourceName,
+                                 UUID rootNodeUuid,
+                                 Cache<UUID, MapNode> cache ) {
+        super(sourceName, rootNodeUuid, null);
+        assert cache != null;
+        this.cache = cache;
+        initialize();
+    }
+
+    public JBossCacheRepository( String sourceName,
+                                 UUID rootNodeUuid,
+                                 String defaultWorkspaceName,
+                                 Cache<UUID, MapNode> cache ) {
+        super(sourceName, rootNodeUuid, defaultWorkspaceName);
+
+        assert cache != null;
+        this.cache = cache;
+        
+        initialize();
+    }
+
+    @Override
+    protected MapWorkspace createWorkspace( ExecutionContext context,
+                                            String name ) {
+        assert name != null;
+        assert cache != null;
+        Node<UUID, MapNode> newWorkspaceNode = cache.getRoot().addChild(Fqn.fromElements(name));
+        return new Workspace(this, name, newWorkspaceNode);
+    }
+
+    protected class Workspace extends AbstractMapWorkspace {
+        private final Node<UUID, MapNode> workspaceNode;
+
+        public Workspace( MapRepository repository,
+                          String name,
+                          Node<UUID, MapNode> workspaceNode ) {
+            super(repository, name);
+
+            this.workspaceNode = workspaceNode;
+            initialize();
+        }
+
+        protected void addNodeToMap( MapNode node ) {
+            assert node != null;
+            workspaceNode.put(node.getUuid(), node);
+        }
+
+        protected MapNode removeNodeFromMap( UUID nodeUuid ) {
+            assert nodeUuid != null;
+            return workspaceNode.remove(nodeUuid);
+        }
+
+        protected void removeAllNodesFromMap() {
+            workspaceNode.clearData();
+        }
+
+        public MapNode getNode( UUID nodeUuid ) {
+            assert nodeUuid != null;
+            return workspaceNode.get(nodeUuid);
+        }
+    }
+
+}


Property changes on: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java
___________________________________________________________________
Name: svn:keywords
   + Id Revision
Name: svn:eol-style
   + LF

Deleted: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -1,1032 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of 
- * individual contributors.
- *
- * Unless otherwise indicated, all code in JBoss DNA is licensed
- * to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- * 
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.connector.jbosscache;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.jboss.cache.Cache;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.Node;
-import org.jboss.dna.common.util.Logger;
-import org.jboss.dna.graph.DnaLexicon;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.Location;
-import org.jboss.dna.graph.connector.RepositorySourceException;
-import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
-import org.jboss.dna.graph.observe.Observer;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.PathFactory;
-import org.jboss.dna.graph.property.PathNotFoundException;
-import org.jboss.dna.graph.property.Property;
-import org.jboss.dna.graph.property.PropertyFactory;
-import org.jboss.dna.graph.property.UuidFactory;
-import org.jboss.dna.graph.request.CloneWorkspaceRequest;
-import org.jboss.dna.graph.request.CopyBranchRequest;
-import org.jboss.dna.graph.request.CreateNodeRequest;
-import org.jboss.dna.graph.request.CreateWorkspaceRequest;
-import org.jboss.dna.graph.request.DeleteBranchRequest;
-import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
-import org.jboss.dna.graph.request.GetWorkspacesRequest;
-import org.jboss.dna.graph.request.InvalidRequestException;
-import org.jboss.dna.graph.request.InvalidWorkspaceException;
-import org.jboss.dna.graph.request.MoveBranchRequest;
-import org.jboss.dna.graph.request.ReadAllChildrenRequest;
-import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
-import org.jboss.dna.graph.request.Request;
-import org.jboss.dna.graph.request.UpdatePropertiesRequest;
-import org.jboss.dna.graph.request.UuidConflictBehavior;
-import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
-import org.jboss.dna.graph.request.processor.RequestProcessor;
-
-/**
- * A {@link RequestProcessor} implementation that operates upon a {@link Cache JBoss Cache} instance for each workspace in the
- * {@link JBossCacheSource source}.
- * <p>
- * This processor only uses {@link Location} objects with {@link Location#getPath() paths}. Even though every node in the cache is
- * automatically assigned a UUID (and all operations properly handle UUIDs), these UUIDs are not included in the {@link Location}
- * objects because the processor is unable to search the cache to find nodes by UUID.
- * </p>
- */
-public class JBossCacheRequestProcessor extends RequestProcessor {
-
-    private final JBossCacheWorkspaces workspaces;
-    private final boolean creatingWorkspacesAllowed;
-    private final String defaultWorkspaceName;
-    private final PathFactory pathFactory;
-    private final PropertyFactory propertyFactory;
-    private final UuidFactory uuidFactory;
-    private Path.Segment dnaUuidsSegment;
-
-    /**
-     * @param sourceName the name of the source in which this processor is operating
-     * @param context the execution context in which this processor operates
-     * @param observer the observer to which events should be published; may be null if the events are not be published
-     * @param workspaces the manager for the workspaces
-     * @param defaultWorkspaceName the name of the default workspace; never null
-     * @param creatingWorkspacesAllowed true if clients can create new workspaces, or false otherwise
-     */
-    JBossCacheRequestProcessor( String sourceName,
-                                ExecutionContext context,
-                                Observer observer,
-                                JBossCacheWorkspaces workspaces,
-                                String defaultWorkspaceName,
-                                boolean creatingWorkspacesAllowed ) {
-        super(sourceName, context, observer);
-        assert workspaces != null;
-        assert defaultWorkspaceName != null;
-        this.workspaces = workspaces;
-        this.creatingWorkspacesAllowed = creatingWorkspacesAllowed;
-        this.defaultWorkspaceName = defaultWorkspaceName;
-        this.pathFactory = context.getValueFactories().getPathFactory();
-        this.propertyFactory = context.getPropertyFactory();
-        this.uuidFactory = context.getValueFactories().getUuidFactory();
-        this.dnaUuidsSegment = pathFactory.createSegment(JBossCacheLexicon.UUIDS);
-    }
-
-    @Override
-    public void process( ReadAllChildrenRequest request ) {
-        // Look up the cache and the node ...
-        Cache<Name, Object> cache = getCache(request, request.inWorkspace());
-        if (cache == null) return;
-        Path nodePath = request.of().getPath();
-        Node<Name, Object> node = getNode(request, cache, nodePath);
-        if (node == null) return;
-
-        // Get the names of the children, using the child list ...
-        Path.Segment[] childList = (Path.Segment[])node.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
-        if (childList != null) {
-            for (Path.Segment child : childList) {
-                request.addChild(Location.create(pathFactory.create(nodePath, child)));
-            }
-        }
-        request.setActualLocationOfNode(Location.create(nodePath));
-        setCacheableInfo(request);
-    }
-
-    @Override
-    public void process( ReadAllPropertiesRequest request ) {
-        // Look up the cache and the node ...
-        Cache<Name, Object> cache = getCache(request, request.inWorkspace());
-        if (cache == null) return;
-        Path nodePath = request.at().getPath();
-        Node<Name, Object> node = getNode(request, cache, nodePath);
-        if (node == null) return;
-
-        // Get the properties on the node ...
-        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);
-        }
-        request.setActualLocationOfNode(Location.create(nodePath));
-        setCacheableInfo(request);
-    }
-
-    @Override
-    @SuppressWarnings( "unchecked" )
-    public void process( CreateNodeRequest request ) {
-        // Look up the cache and the node ...
-        Cache<Name, Object> cache = getCache(request, request.inWorkspace());
-        if (cache == null) return;
-        Path parent = request.under().getPath();
-        Node<Name, Object> parentNode = getNode(request, cache, parent);
-        if (parentNode == null) return;
-
-        // 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(cache, parentNode, request.named(), null, 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 ...
-        UUID uuid = uuidFactory.create();
-        node.put(DnaLexicon.UUID, uuid);
-        // 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);
-        }
-
-        mapUuid(cache, uuid, node.getFqn());
-        Path nodePath = pathFactory.create(parent, newSegment);
-        request.setActualLocationOfNode(Location.create(nodePath));
-        recordChange(request);
-    }
-
-    @Override
-    public void process( UpdatePropertiesRequest request ) {
-        // Look up the cache and the node ...
-        Cache<Name, Object> cache = getCache(request, request.inWorkspace());
-        if (cache == null) return;
-        Path nodePath = request.on().getPath();
-        Node<Name, Object> node = getNode(request, cache, nodePath);
-        if (node == null) return;
-
-        // Now set (or remove) the properties to the supplied node ...
-        for (Map.Entry<Name, Property> entry : request.properties().entrySet()) {
-            Name propName = entry.getKey();
-            // Don't allow the child list property to be removed or changed
-            if (propName.equals(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST)) continue;
-
-            Property property = entry.getValue();
-            if (property == null) {
-                node.remove(propName);
-                continue;
-            }
-            Object value = null;
-            if (property.isSingle()) {
-                value = property.iterator().next();
-            } else {
-                value = property.getValuesAsArray();
-            }
-            node.put(propName, value);
-        }
-        request.setActualLocationOfNode(Location.create(nodePath));
-        recordChange(request);
-    }
-
-    @Override
-    public void process( CopyBranchRequest request ) {
-        // Look up the caches ...
-        Cache<Name, Object> fromCache = getCache(request, request.fromWorkspace());
-        if (fromCache == null) return;
-        Cache<Name, Object> intoCache = getCache(request, request.intoWorkspace());
-        if (intoCache == null) return;
-
-        // Look up the current node and the new parent (both of which must exist) ...
-        Path nodePath = request.from().getPath();
-        Node<Name, Object> node = getNode(request, fromCache, nodePath);
-        if (node == null) return;
-        Path newParentPath = request.into().getPath();
-        Node<Name, Object> newParent = getNode(request, intoCache, newParentPath);
-        if (newParent == null) return;
-
-        if (UuidConflictBehavior.THROW_EXCEPTION.equals(request.uuidConflictBehavior())) {
-            // Build a list of all the UUIDs in the source branch
-            Set<UUID> uuidsFromSource = new HashSet<UUID>();
-            LinkedList<Node<Name, Object>> nodesToVisit = new LinkedList<Node<Name, Object>>();
-            nodesToVisit.add(node);
-
-            while (!nodesToVisit.isEmpty()) {
-                Node<Name, Object> nodeToCheck = nodesToVisit.removeFirst();
-                UUID uuid = uuidFactory.create(nodeToCheck.get(DnaLexicon.UUID));
-                if (uuid != null) uuidsFromSource.add(uuid);
-
-                nodesToVisit.addAll(nodeToCheck.getChildren());
-            }
-
-            // If any of the UUIDS currently exist in this workspace, throw an exception
-            for (UUID uuid : uuidsFromSource) {
-                Fqn<Path.Segment> path;
-                if (null != (path = getFullyQualifiedName(intoCache, uuid))) {
-                    String pathAsString = path.toString();
-                    throw new UuidAlreadyExistsException(this.getSourceName(), uuid, pathAsString, request.intoWorkspace());
-                }
-            }
-        }
-
-        // Copy the branch ...
-        Name desiredName = request.desiredName();
-        Path.Segment newSegment = copyNode(intoCache,
-                                           node,
-                                           newParent,
-                                           desiredName,
-                                           null,
-                                           true,
-                                           request.uuidConflictBehavior(),
-                                           null,
-                                           getExecutionContext());
-
-        mapUuids(intoCache, Fqn.fromRelativeElements(Fqn.fromList(newParentPath.getSegmentsList()), newSegment));
-        Path newPath = pathFactory.create(newParentPath, newSegment);
-        request.setActualLocations(Location.create(nodePath), Location.create(newPath));
-        recordChange(request);
-    }
-
-    @SuppressWarnings( "unchecked" )
-    private boolean deleteNode( Cache<Name, Object> cache,
-                                Node<Name, Object> node ) {
-        Fqn<Path.Segment> nodeFqn = node.getFqn();
-
-        removeUuids(cache, nodeFqn);
-        Path.Segment nameOfRemovedNode = (Path.Segment)nodeFqn.getLastElement();
-        if (cache.removeNode(node.getFqn())) {
-            removeFromChildList(cache, node.getParent(), nameOfRemovedNode, getExecutionContext());
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void process( DeleteBranchRequest request ) {
-        // Look up the cache and the node ...
-        Cache<Name, Object> cache = getCache(request, request.inWorkspace());
-        if (cache == null) return;
-        Path nodePath = request.at().getPath();
-        Node<Name, Object> node = getNode(request, cache, nodePath);
-        if (node == null) return;
-
-        if (deleteNode(cache, node)) {
-            request.setActualLocationOfNode(Location.create(nodePath));
-            recordChange(request);
-        } else {
-            String msg = JBossCacheConnectorI18n.unableToDeleteBranch.text(getSourceName(), request.inWorkspace(), nodePath);
-            request.setError(new RepositorySourceException(msg));
-        }
-    }
-
-    @Override
-    @SuppressWarnings( "unchecked" )
-    public void process( MoveBranchRequest request ) {
-        // Look up the caches ...
-        Cache<Name, Object> cache = getCache(request, request.inWorkspace());
-        if (cache == null) return;
-
-        // Look up the current node and the new parent (both of which must exist) ...
-        Path nodePath = request.from().getPath();
-        Node<Name, Object> node = getNode(request, cache, nodePath);
-        if (node == null) return;
-        Path newParentPath;
-
-        if (request.into() != null) {
-            newParentPath = request.into().getPath();
-        } else {
-            // into() and before() can't both be null
-            assert request.before() != null;
-            newParentPath = request.before().getPath().getParent();
-        }
-
-        Path.Segment beforeNodeName = request.before() != null ? request.before().getPath().getLastSegment() : null;
-        Node<Name, Object> newParent = getNode(request, cache, newParentPath);
-        if (newParent == null) return;
-
-        removeUuids(cache, node.getFqn());
-
-        // Copy the branch and use the same UUIDs ...
-        Name desiredName = request.desiredName();
-        Path.Segment newSegment = copyNode(cache,
-                                           node,
-                                           newParent,
-                                           desiredName,
-                                           beforeNodeName,
-                                           true,
-                                           UuidConflictBehavior.THROW_EXCEPTION,
-                                           null,
-                                           getExecutionContext());
-        mapUuids(cache, node.getFqn());
-        // Now delete the old node ...
-        Node<Name, Object> oldParent = node.getParent();
-        boolean removed = oldParent.removeChild(node.getFqn().getLastElement());
-        assert removed;
-        Path.Segment nameOfRemovedNode = nodePath.getLastSegment();
-        removeFromChildList(cache, oldParent, nameOfRemovedNode, getExecutionContext());
-
-        Path newPath = pathFactory.create(newParentPath, newSegment);
-        request.setActualLocations(Location.create(nodePath), Location.create(newPath));
-        recordChange(request);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.VerifyWorkspaceRequest)
-     */
-    @Override
-    public void process( VerifyWorkspaceRequest request ) {
-        String workspaceName = request.workspaceName();
-        if (workspaceName == null) workspaceName = defaultWorkspaceName;
-
-        Cache<Name, Object> cache = workspaces.getWorkspace(workspaceName, false);
-        if (cache == null) {
-            String msg = JBossCacheConnectorI18n.workspaceDoesNotExist.text(getSourceName(), workspaceName);
-            request.setError(new InvalidWorkspaceException(msg));
-        } else {
-            Fqn<Path.Segment> rootName = Fqn.root();
-            UUID uuid = uuidFactory.create(cache.get(rootName, DnaLexicon.UUID));
-            if (uuid == null) {
-                uuid = uuidFactory.create();
-                cache.put(rootName, DnaLexicon.UUID, uuid);
-            }
-            request.setActualRootLocation(Location.create(pathFactory.createRootPath()));
-            request.setActualWorkspaceName(workspaceName);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.GetWorkspacesRequest)
-     */
-    @Override
-    public void process( GetWorkspacesRequest request ) {
-        request.setAvailableWorkspaceNames(workspaces.getWorkspaceNames());
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CreateWorkspaceRequest)
-     */
-    @Override
-    public void process( CreateWorkspaceRequest request ) {
-        String workspaceName = request.desiredNameOfNewWorkspace();
-        if (!creatingWorkspacesAllowed) {
-            String msg = JBossCacheConnectorI18n.unableToCreateWorkspaces.text(getSourceName(), workspaceName);
-            request.setError(new InvalidRequestException(msg));
-            return;
-        }
-        // Try to create the workspace ...
-        Cache<Name, Object> cache = workspaces.getWorkspace(workspaceName, creatingWorkspacesAllowed);
-        if (cache == null) {
-            String msg = JBossCacheConnectorI18n.unableToCreateWorkspace.text(getSourceName(), workspaceName);
-            request.setError(new InvalidWorkspaceException(msg));
-            return;
-        }
-        // Make sure the root node has a UUID ...
-        Fqn<Path.Segment> rootName = Fqn.root();
-        UUID uuid = uuidFactory.create(cache.get(rootName, DnaLexicon.UUID));
-        if (uuid == null) {
-            uuid = uuidFactory.create();
-            cache.put(rootName, DnaLexicon.UUID, uuid);
-            mapUuid(cache, uuid, rootName);
-        }
-        request.setActualRootLocation(Location.create(pathFactory.createRootPath()));
-        request.setActualWorkspaceName(workspaceName);
-        recordChange(request);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CloneWorkspaceRequest)
-     */
-    @Override
-    @SuppressWarnings( "unchecked" )
-    public void process( CloneWorkspaceRequest request ) {
-        String fromWorkspaceName = request.nameOfWorkspaceToBeCloned();
-        String toWorkspaceName = request.desiredNameOfTargetWorkspace();
-        if (!creatingWorkspacesAllowed) {
-            String msg = JBossCacheConnectorI18n.unableToCloneWorkspaces.text(getSourceName(), fromWorkspaceName, toWorkspaceName);
-            request.setError(new InvalidRequestException(msg));
-            return;
-        }
-        // Make sure there is already a workspace that we're cloning ...
-        Cache<Name, Object> fromCache = workspaces.getWorkspace(fromWorkspaceName, false);
-        if (fromCache == null) {
-            String msg = JBossCacheConnectorI18n.workspaceDoesNotExist.text(getSourceName(), fromWorkspaceName);
-            request.setError(new InvalidWorkspaceException(msg));
-            return;
-        }
-
-        // Try to create a new workspace with the target name ...
-        Cache<Name, Object> intoCache = workspaces.createWorkspace(toWorkspaceName);
-        if (intoCache == null) {
-            // Couldn't create it because one already exists ...
-            String msg = JBossCacheConnectorI18n.workspaceAlreadyExists.text(getSourceName(), toWorkspaceName);
-            request.setError(new InvalidWorkspaceException(msg));
-            return;
-        }
-
-        // And finally copy the contents ...
-        Fqn<Path.Segment> rootName = Fqn.root();
-        Node<Name, Object> fromRoot = fromCache.getNode(rootName);
-        Node<Name, Object> intoRoot = intoCache.getNode(rootName);
-        intoRoot.clearData();
-        intoRoot.putAll(fromRoot.getData());
-        ExecutionContext context = getExecutionContext();
-
-        // Loop over each child and copy it ...
-        for (Node<Name, Object> child : fromRoot.getChildren()) {
-            copyNode(intoCache, child, intoRoot, null, null, true, UuidConflictBehavior.THROW_EXCEPTION, null, context);
-        }
-
-        mapUuids(intoCache, intoRoot.getFqn());
-        // Copy the list of child segments in the root (this maintains the order of the children) ...
-        Path.Segment[] childNames = (Path.Segment[])fromRoot.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
-        intoRoot.put(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST, childNames);
-        recordChange(request);
-    }
-
-    /**
-     * {@inheritDoc}
-     * 
-     * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DestroyWorkspaceRequest)
-     */
-    @Override
-    public void process( DestroyWorkspaceRequest request ) {
-        Cache<Name, Object> fromCache = workspaces.getWorkspace(request.workspaceName(), false);
-        if (fromCache == null) {
-            String msg = JBossCacheConnectorI18n.workspaceDoesNotExist.text(getSourceName(), request.workspaceName());
-            request.setError(new InvalidWorkspaceException(msg));
-            return;
-        }
-        request.setActualRootLocation(Location.create(pathFactory.createRootPath()));
-        recordChange(request);
-    }
-
-    // ----------------------------------------------------------------------------------------------------------------
-    // Utility methods
-    // ----------------------------------------------------------------------------------------------------------------
-
-    /**
-     * Obtain the appropriate cache for the supplied workspace name, or set an error on the request if the workspace does not
-     * exist (and could not or should not be created).
-     * 
-     * @param request the request
-     * @param workspaceName the workspace name
-     * @return the cache, or null if there is no such workspace
-     */
-    protected Cache<Name, Object> getCache( Request request,
-                                            String workspaceName ) {
-        if (workspaceName == null) workspaceName = defaultWorkspaceName;
-        Cache<Name, Object> cache = workspaces.getWorkspace(workspaceName, creatingWorkspacesAllowed);
-        if (cache == null && request != null) {
-            String msg = JBossCacheConnectorI18n.workspaceDoesNotExist.text(getSourceName(), workspaceName);
-            request.setError(new InvalidWorkspaceException(msg));
-        }
-        return cache;
-    }
-
-    protected Fqn<Path.Segment> getFullyQualifiedName( Path path ) {
-        assert path != null;
-        return Fqn.fromList(path.getSegmentsList());
-    }
-
-    /**
-     * Get a relative fully-qualified name that consists only of the supplied segment.
-     * 
-     * @param pathSegment the segment from which the fully qualified name is to be created
-     * @return the relative fully-qualified name
-     */
-    protected Fqn<Path.Segment> getFullyQualifiedName( Path.Segment pathSegment ) {
-        assert pathSegment != null;
-        return Fqn.fromElements(pathSegment);
-    }
-
-    @SuppressWarnings( "unchecked" )
-    protected Fqn<Path.Segment> getFullyQualifiedName( Cache<Name, Object> cache,
-                                                       UUID uuid ) {
-        assert cache != null;
-        assert uuid != null;
-
-        Fqn<Path.Segment> uuidFqn = Fqn.fromElements(dnaUuidsSegment, pathFactory.createSegment(uuid.toString()));
-
-        return (Fqn<Path.Segment>)cache.get(uuidFqn, JBossCacheLexicon.FQN);
-    }
-
-    protected Path getPath( PathFactory factory,
-                            Fqn<Path.Segment> fqn ) {
-        List<Path.Segment> segments = fqn.peekElements();
-        return factory.create(factory.createRootPath(), segments);
-    }
-
-    protected void removeUuid( Cache<Name, Object> cache,
-                               UUID uuid ) {
-        assert cache != null;
-        assert uuid != null;
-
-        Fqn<Path.Segment> uuidFqn = Fqn.fromElements(pathFactory.createSegment(JBossCacheLexicon.UUIDS),
-                                                     pathFactory.createSegment(uuid.toString()));
-
-        removeFromChildList(cache,
-                            getNode(null, cache, pathFactory.create(JBossCacheLexicon.UUIDS)),
-                            pathFactory.createSegment(uuid.toString()),
-                            getExecutionContext());
-        cache.removeNode(uuidFqn);
-    }
-
-    @SuppressWarnings( "unchecked" )
-    protected void mapUuid( Cache<Name, Object> cache,
-                            UUID uuid,
-                            Fqn<Path.Segment> path ) {
-        assert cache != null;
-        assert uuid != null;
-
-        Fqn<Path.Segment> uuidsFqn = Fqn.fromElements(this.dnaUuidsSegment);
-
-        Node uuidsNode = cache.getNode(uuidsFqn);
-        if (uuidsNode == null) {
-            uuidsNode = cache.getRoot().addChild(uuidsFqn);
-            updateChildList(cache, cache.getRoot(), this.dnaUuidsSegment.getName(), null, this.getExecutionContext(), true);
-        }
-
-        assert uuidsNode != null : this.dnaUuidsSegment.getName() + "=" + uuidsFqn;
-        Path.Segment uuidSegment = pathFactory.createSegment(uuid.toString());
-
-        if (!uuidsNode.getChildrenNames().contains(uuidSegment)) {
-            Path.Segment newSegment = updateChildList(cache,
-                                                      uuidsNode,
-                                                      uuidSegment.getName(),
-                                                      null,
-                                                      this.getExecutionContext(),
-                                                      true);
-            assert newSegment.getIndex() == 1 : "Should not have SNS under uuids branch";
-        }
-
-        Fqn<Path.Segment> uuidFqn = Fqn.fromRelativeElements(uuidsFqn, uuidSegment);
-
-        cache.put(uuidFqn, JBossCacheLexicon.FQN, path);
-        assert cache.getNode(uuidFqn) != null;
-        assert cache.get(uuidFqn, JBossCacheLexicon.FQN) != null;
-        assert path.equals(getFullyQualifiedName(cache, uuid)) : path + " => " + getFullyQualifiedName(cache, uuid);
-    }
-
-    protected void mapUuids( Cache<Name, Object> cache,
-                             Fqn<Path.Segment> path ) {
-        Node<Name, Object> node = cache.getNode(path);
-        assert node != null : path.toString();
-        UUID uuid = (UUID)node.get(DnaLexicon.UUID);
-        if (uuid != null) {
-            mapUuid(cache, uuid, path);
-            assert getFullyQualifiedName(cache, uuid).equals(path);
-        }
-
-        Path.Segment[] childNamesProperty = (Path.Segment[])node.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
-        if (childNamesProperty == null) return;
-
-        for (Path.Segment childName : childNamesProperty) {
-            Fqn<Path.Segment> childPath = Fqn.fromRelativeElements(path, childName);
-            mapUuids(cache, childPath);
-        }
-    }
-
-    protected void removeUuids( Cache<Name, Object> cache,
-                                Fqn<Path.Segment> path ) {
-        Node<Name, Object> node = cache.getNode(path);
-        assert node != null : path.toString();
-        UUID uuid = (UUID)node.get(DnaLexicon.UUID);
-
-        if (uuid != null) removeUuid(cache, uuid);
-
-        Path.Segment[] childNamesProperty = (Path.Segment[])node.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
-        if (childNamesProperty == null) return;
-
-        for (Path.Segment childName : childNamesProperty) {
-            Fqn<Path.Segment> childPath = Fqn.fromRelativeElements(path, childName);
-            removeUuids(cache, childPath);
-        }
-    }
-
-    protected Node<Name, Object> getNode( Request request,
-                                          Cache<Name, Object> cache,
-                                          Path path ) {
-        ExecutionContext context = getExecutionContext();
-        if (path == null) {
-            String msg = JBossCacheConnectorI18n.locationsMustHavePath.text(getSourceName(), request);
-            request.setError(new InvalidRequestException(msg));
-            return null;
-        }
-        // Look up the node with the supplied path ...
-        Fqn<Path.Segment> fqn = getFullyQualifiedName(path);
-        Node<Name, Object> node = cache.getNode(fqn);
-
-        if (node == null) {
-            String nodePath = path.getString(context.getNamespaceRegistry());
-            Path lowestExisting = null;
-            while (fqn != null) {
-                fqn = fqn.getParent();
-                node = cache.getNode(fqn);
-                if (node != null) {
-                    lowestExisting = getPath(context.getValueFactories().getPathFactory(), fqn);
-                    fqn = null;
-                }
-            }
-            request.setError(new PathNotFoundException(Location.create(path), lowestExisting,
-                                                       JBossCacheConnectorI18n.nodeDoesNotExist.text(nodePath)));
-            node = null;
-        }
-        return node;
-
-    }
-
-    /**
-     * @param newCache the cache into which the node is to be copied
-     * @param original the node to be copied
-     * @param newParent the new parent of the node to be copied
-     * @param desiredName the desired name of the node in the new location
-     * @param beforeNodeName the node before which the new node should be placed
-     * @param recursive if this is a deep copy
-     * @param uuidConflictBehavior indicates whether the original UUIDs should be used for the copies or new UUIDs should be used
-     * @param count the count of nodes affected by the operation
-     * @param context the execution context that provides the path factory to be used to create the new path name
-     * @return the path segment that identifies the new node under its new parent
-     */
-    @SuppressWarnings( "unchecked" )
-    protected Path.Segment copyNode( Cache<Name, Object> newCache,
-                                     Node<Name, Object> original,
-                                     Node<Name, Object> newParent,
-                                     Name desiredName,
-                                     Path.Segment beforeNodeName,
-                                     boolean recursive,
-                                     UuidConflictBehavior uuidConflictBehavior,
-                                     AtomicInteger count,
-                                     ExecutionContext context ) {
-        assert original != null;
-        assert newParent != null;
-        // Get or create the new node ...
-        Path.Segment name = desiredName != null ? context.getValueFactories().getPathFactory().createSegment(desiredName) : (Path.Segment)original.getFqn()
-                                                                                                                                                  .getLastElement();
-
-        // 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(newCache, newParent, name.getName(), beforeNodeName, context, true);
-        Node<Name, Object> copy = newParent.addChild(getFullyQualifiedName(newSegment));
-        assert checkChildren(newParent);
-        // Copy the properties ...
-        copy.clearData();
-        copy.putAll(original.getData());
-        copy.remove(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST); // will be reset later ...
-
-        UUID uuid;
-        switch (uuidConflictBehavior) {
-            case ALWAYS_CREATE_NEW_UUID:
-                uuid = UUID.randomUUID();
-                break;
-            case REPLACE_EXISTING_NODE:
-                uuid = uuidFactory.create(original.get(DnaLexicon.UUID));
-                Fqn<?> existingPath = getFullyQualifiedName(newCache, uuid);
-                if (existingPath != null) {
-                    Node<Name, Object> existingNode = newCache.getNode(existingPath);
-                    deleteNode(newCache, existingNode);
-                }
-
-                break;
-            case THROW_EXCEPTION:
-                uuid = uuidFactory.create(original.get(DnaLexicon.UUID));
-                break;
-            default:
-                throw new IllegalStateException("Unexpected UuidConflictBehavior value: " + uuidConflictBehavior);
-        }
-        copy.put(DnaLexicon.UUID, uuid);
-
-        if (count != null) count.incrementAndGet();
-        if (recursive) {
-            // Loop over each child and call this method ...
-            for (Node<Name, Object> child : original.getChildren()) {
-                copyNode(newCache, child, copy, null, null, true, uuidConflictBehavior, count, context);
-            }
-        }
-        mapUuids(newCache, copy.getFqn());
-        assert getFullyQualifiedName(newCache, uuid) != null;
-        return newSegment;
-    }
-
-    /**
-     * Update (or create) the array of {@link Path.Segment path segments} for the children of the supplied node. This array
-     * maintains the ordered list of children (since the {@link Cache} does not maintain the order). Invoking this method will
-     * change any existing children that a {@link Path.Segment#getName() name part} that matches the supplied
-     * <code>changedName</code> to have the appropriate {@link Path.Segment#getIndex() same-name sibling index}.
-     * 
-     * @param cache the cache in which the parent exists ...
-     * @param parent the parent node; may not be null
-     * @param changedName the name that should be compared to the existing node siblings to determine whether the same-name
-     *        sibling indexes should be updated; may not be null
-     * @param beforeNodeName the name of the node before which this node should be placed; null indicates that this node should be
-     *        added as the last child under the node
-     * @param context the execution context; may not be null
-     * @param addChildWithName true if a new child with the supplied name is to be added to the children (but which does not yet
-     *        exist in the node's children)
-     * @return the path segment for the new child, or null if <code>addChildWithName</code> was false
-     */
-    protected Path.Segment updateChildList( Cache<Name, Object> cache,
-                                            Node<Name, Object> parent,
-                                            Name changedName,
-                                            Path.Segment beforeNodeName,
-                                            ExecutionContext context,
-                                            boolean addChildWithName ) {
-        assert parent != null;
-        assert changedName != null;
-        assert context != null;
-        Set<Node<Name, Object>> children = parent.getChildren();
-        if (children.isEmpty() && !addChildWithName) return null;
-
-        // Go through the children, looking for any children with the same name as the 'changedName'
-        List<ChildInfo> childrenWithChangedName = new LinkedList<ChildInfo>();
-        Path.Segment[] childNames = (Path.Segment[])parent.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
-        int index = 0;
-        int snsIndex = 0;
-        boolean foundBeforeNode = false;
-        if (childNames != null) {
-            for (Path.Segment childName : childNames) {
-                if (childName.equals(beforeNodeName)) {
-                    foundBeforeNode = true;
-                    // And add a child info for the new node ...
-                    ChildInfo info = new ChildInfo(null, snsIndex++);
-                    childrenWithChangedName.add(info);
-                }
-                if (childName.getName().equals(changedName)) {
-                    ChildInfo info = new ChildInfo(childName, snsIndex);
-                    childrenWithChangedName.add(info);
-                }
-
-                snsIndex++;
-                if (!foundBeforeNode) index++;
-            }
-
-        }
-        if (addChildWithName) {
-            // Make room for the new child at the end of the array ...
-            if (childNames == null) {
-                childNames = new Path.Segment[1];
-            } else {
-                int numExisting = childNames.length;
-                Path.Segment[] newChildNames = new Path.Segment[numExisting + 1];
-                System.arraycopy(childNames, 0, newChildNames, 0, index);
-
-                if (index != numExisting) {
-                    System.arraycopy(childNames, index, newChildNames, index + 1, numExisting - index);
-                }
-                childNames = newChildNames;
-            }
-
-            if (!foundBeforeNode) {
-                // Make sure that we add a record for the new node if it hasn't previously been added
-                ChildInfo info = new ChildInfo(null, index);
-                childrenWithChangedName.add(info);
-
-            }
-            Path.Segment newSegment = context.getValueFactories().getPathFactory().createSegment(changedName);
-            childNames[index] = newSegment;
-        }
-        assert childNames != null;
-
-        // Now process the children with the same name, which may include a child info for the new node ...
-        assert childrenWithChangedName.isEmpty() == false;
-        if (childrenWithChangedName.size() == 1) {
-            // The child should have no indexes ...
-            ChildInfo child = childrenWithChangedName.get(0);
-            if (child.segment != null && child.segment.hasIndex()) {
-                // The existing child needs to have a new index ..
-                Path.Segment newSegment = context.getValueFactories().getPathFactory().createSegment(changedName);
-                // Replace the child with the correct FQN ...
-                changeNodeName(cache, parent, child.segment, newSegment, context);
-                // Change the segment in the child list ...
-                childNames[child.childIndex] = newSegment;
-            }
-        } else {
-            // There is more than one child with the same name ...
-            int i = 0;
-            for (ChildInfo child : childrenWithChangedName) {
-                if (child.segment != null) {
-                    // Determine the new name and index ...
-                    Path.Segment newSegment = context.getValueFactories().getPathFactory().createSegment(changedName, i + 1);
-                    // Replace the child with the correct FQN ...
-                    changeNodeName(cache, parent, child.segment, newSegment, context);
-                    // Change the segment in the child list ...
-                    childNames[child.childIndex] = newSegment;
-                } else {
-                    // Determine the new name and index ...
-                    Path.Segment newSegment = context.getValueFactories().getPathFactory().createSegment(changedName, i + 1);
-                    childNames[child.childIndex] = newSegment;
-                }
-                ++i;
-            }
-        }
-
-        // Record the list of children as a property on the parent ...
-        // (Do this last, as it doesn't need to be done if there's an exception in the above logic)
-        context.getLogger(getClass()).trace("Updating child list of {0} to: {1}", parent.getFqn(), Arrays.asList(childNames));
-        parent.put(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST, childNames); // replaces any existing value
-
-        if (addChildWithName) {
-            // Return the segment for the new node ...
-            return childNames[index];
-        }
-        return null;
-    }
-
-    /**
-     * Update the array of {@link Path.Segment path segments} for the children of the supplied node, based upon a node being
-     * removed. This array maintains the ordered list of children (since the {@link Cache} does not maintain the order). Invoking
-     * this method will change any existing children that a {@link Path.Segment#getName() name part} that matches the supplied
-     * <code>changedName</code> to have the appropriate {@link Path.Segment#getIndex() same-name sibling index}.
-     * 
-     * @param cache the cache in which the parent exists ...
-     * @param parent the parent node; may not be null
-     * @param removedNode the segment of the node that was removed, which signals to look for node with the same name; may not be
-     *        null
-     * @param context the execution context; may not be null
-     */
-    protected void removeFromChildList( Cache<Name, Object> cache,
-                                        Node<Name, Object> parent,
-                                        Path.Segment removedNode,
-                                        ExecutionContext context ) {
-        assert parent != null;
-        assert context != null;
-        Set<Node<Name, Object>> children = parent.getChildren();
-        if (children.isEmpty()) {
-            parent.put(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST, null); // replaces any existing value
-            return;
-        }
-
-        // Go through the children, looking for any children with the same name as the 'changedName'
-        Path.Segment[] childNames = (Path.Segment[])parent.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
-        assert childNames != null;
-        int snsIndex = removedNode.getIndex();
-        int index = 0;
-        Path.Segment[] newChildNames = new Path.Segment[childNames.length - 1];
-        for (Path.Segment childName : childNames) {
-
-            if (!childName.getName().equals(removedNode.getName())) {
-                newChildNames[index] = childName;
-                index++;
-            } else {
-                // The name matches ...
-                if (childName.getIndex() < snsIndex) {
-                    // Just copy ...
-                    newChildNames[index] = childName;
-                    index++;
-                } else if (childName.getIndex() == snsIndex) {
-                    // don't copy ...
-                } else {
-                    // Append an updated segment ...
-                    Path.Segment newSegment = context.getValueFactories()
-                                                     .getPathFactory()
-                                                     .createSegment(childName.getName(), childName.getIndex() - 1);
-                    newChildNames[index] = newSegment;
-                    // Replace the child with the correct FQN ...
-                    changeNodeName(cache, parent, childName, newSegment, context);
-                    index++;
-                }
-            }
-        }
-        parent.put(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST, newChildNames); // replaces any existing value
-    }
-
-    protected boolean checkChildren( Node<Name, Object> parent ) {
-        Path.Segment[] childNamesProperty = (Path.Segment[])parent.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
-        Set<Object> childNames = parent.getChildrenNames();
-        boolean result = true;
-        if (childNamesProperty.length != childNames.size()) result = false;
-        if (!result) throw new IllegalStateException(parent.getFqn().toString());
-        for (int i = 0; i != childNamesProperty.length; ++i) {
-            if (!childNames.contains(childNamesProperty[i])) result = false;
-        }
-        if (!result) throw new IllegalStateException(parent.getFqn().toString());
-        if (!result) {
-            List<Path.Segment> names = new ArrayList<Path.Segment>();
-            for (Object name : childNames) {
-                assert name instanceof Path.Segment : parent.getFqn().toString() + "/" + name.toString();
-                names.add((Path.Segment)name);
-            }
-            Collections.sort(names);
-            Logger.getLogger(getClass()).trace("Child list on {0} is: {1}", parent.getFqn(), childNamesProperty);
-            Logger.getLogger(getClass()).trace("Children of {0} is: {1}", parent.getFqn(), names);
-        }
-        if (!result) throw new IllegalStateException(parent.getFqn().toString());
-        return result;
-    }
-
-    /**
-     * Utility class used by the
-     * {@link JBossCacheRequestProcessor#updateChildList(Cache, Node, Name, org.jboss.dna.graph.property.Path.Segment, ExecutionContext, boolean)}
-     * method.
-     * 
-     * @author Randall Hauch
-     */
-    private static class ChildInfo {
-        protected final Path.Segment segment;
-        protected final int childIndex;
-
-        protected ChildInfo( Path.Segment childSegment,
-                             int childIndex ) {
-            this.segment = childSegment;
-            this.childIndex = childIndex;
-        }
-
-        @Override
-        public String toString() {
-            return (segment != null ? segment.getString() : "null") + "@" + childIndex;
-        }
-
-    }
-
-    /**
-     * Changes the name of the node in the cache (but does not update the list of child segments stored on the parent).
-     * 
-     * @param cache
-     * @param parent
-     * @param existing
-     * @param newSegment
-     * @param context
-     */
-    @SuppressWarnings( "unchecked" )
-    protected void changeNodeName( Cache<Name, Object> cache,
-                                   Node<Name, Object> parent,
-                                   Path.Segment existing,
-                                   Path.Segment newSegment,
-                                   ExecutionContext context ) {
-        assert parent != null;
-        assert existing != null;
-        assert newSegment != null;
-        assert context != null;
-
-        if (existing.equals(newSegment)) return;
-        context.getLogger(getClass()).trace("Renaming {0} to {1} under {2}", existing, newSegment, parent.getFqn());
-        Node<Name, Object> existingChild = parent.getChild(existing);
-        assert existingChild != null : parent.getFqn().toString() + "/" + existing;
-
-        // JBoss Cache can move a node from one node to another node, but the move doesn't change the name;
-        // since you provide the FQN of the parent location, the name of the node cannot be changed.
-        // Therefore, to compensate, we need to create a new child, copy all of the data, move all of the child
-        // nodes of the old node, then remove the old node.
-
-        // Create the new node ...
-        Node<Name, Object> newChild = parent.addChild(Fqn.fromElements(newSegment));
-        Fqn<Path.Segment> newChildFqn = newChild.getFqn();
-
-        // Copy the data ...
-        newChild.putAll(existingChild.getData());
-
-        // Move the children ...
-        for (Node<Name, Object> grandChild : existingChild.getChildren()) {
-            cache.move(grandChild.getFqn(), newChildFqn);
-        }
-
-        // Remove the existing ...
-        parent.removeChild(existing);
-    }
-}

Modified: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheSource.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -45,11 +45,14 @@
 import javax.naming.Referenceable;
 import javax.naming.StringRefAddr;
 import javax.naming.spi.ObjectFactory;
+import net.jcip.annotations.GuardedBy;
 import net.jcip.annotations.ThreadSafe;
 import org.jboss.cache.Cache;
 import org.jboss.cache.CacheFactory;
 import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.config.ConfigurationException;
 import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.Logger;
 import org.jboss.dna.common.util.StringUtil;
 import org.jboss.dna.graph.DnaLexicon;
 import org.jboss.dna.graph.cache.CachePolicy;
@@ -58,8 +61,11 @@
 import org.jboss.dna.graph.connector.RepositorySource;
 import org.jboss.dna.graph.connector.RepositorySourceCapabilities;
 import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.map.MapNode;
+import org.jboss.dna.graph.connector.map.MapRepositoryConnection;
+import org.jboss.dna.graph.connector.map.MapRepositorySource;
 import org.jboss.dna.graph.observe.Observer;
-import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.request.CreateWorkspaceRequest.CreateConflictBehavior;
 
 /**
  * A repository source that uses a JBoss Cache instance to manage the content. This source is capable of using an existing
@@ -79,7 +85,7 @@
  * @author Randall Hauch
  */
 @ThreadSafe
-public class JBossCacheSource implements RepositorySource, ObjectFactory {
+public class JBossCacheSource implements MapRepositorySource, ObjectFactory {
 
     private static final long serialVersionUID = 2L;
     /**
@@ -114,9 +120,10 @@
     private volatile String defaultWorkspace;
     private volatile String[] predefinedWorkspaces = new String[] {};
     private volatile RepositorySourceCapabilities capabilities = new RepositorySourceCapabilities(true, true, false, true, false);
-    private transient JBossCacheWorkspaces workspaces;
+    private transient JBossCacheRepository repository;
     private transient Context jndiContext;
     private transient RepositoryContext repositoryContext;
+    private final Set<String> repositoryNamesForConfigurationNameProblems = new HashSet<String>();
 
     /**
      * Create a repository source instance.
@@ -435,7 +442,7 @@
             I18n msg = JBossCacheConnectorI18n.propertyIsRequired;
             throw new RepositorySourceException(getName(), msg.text("name"));
         }
-        if (this.workspaces == null) {
+        if (this.repository == null) {
             Context context = getContext();
             if (context == null) {
                 try {
@@ -446,13 +453,13 @@
             }
 
             // Look for a cache factory in JNDI ...
-            CacheFactory<Name, Object> cacheFactory = null;
+            CacheFactory<UUID, MapNode> cacheFactory = null;
             String jndiName = getCacheFactoryJndiName();
             if (jndiName != null && jndiName.trim().length() != 0) {
                 Object object = null;
                 try {
                     object = context.lookup(jndiName);
-                    if (object != null) cacheFactory = (CacheFactory<Name, Object>)object;
+                    if (object != null) cacheFactory = (CacheFactory<UUID, MapNode>)object;
                 } catch (ClassCastException err) {
                     I18n msg = JBossCacheConnectorI18n.objectFoundInJndiWasNotCacheFactory;
                     String className = object != null ? object.getClass().getName() : "null";
@@ -462,27 +469,65 @@
                     throw new RepositorySourceException(getName(), err);
                 }
             }
-            if (cacheFactory == null) cacheFactory = new DefaultCacheFactory<Name, Object>();
+            if (cacheFactory == null) cacheFactory = new DefaultCacheFactory<UUID, MapNode>();
 
-            // Get the default cache configuration name
-            String configName = this.getCacheConfigurationName();
+            // Now create the repository ...
+            this.repository = new JBossCacheRepository(getName(), this.rootNodeUuid, createNewCache(cacheFactory, getName()));
 
             // Create the set of initial names ...
-            Set<String> initialNames = new HashSet<String>();
             for (String initialName : getPredefinedWorkspaceNames())
-                initialNames.add(initialName);
+                repository.createWorkspace(null, initialName, CreateConflictBehavior.DO_NOT_CREATE);
+        
+        }
 
-            // Now create the workspace manager ...
-            this.workspaces = new JBossCacheWorkspaces(getName(), cacheFactory, configName, initialNames, context);
+        return new MapRepositoryConnection(this, this.repository);
+    }
+
+    /**
+     * Method that is responsible for attempting to create a new cache given the supplied workspace name. Note that this is
+     * probably called at most once for each workspace name (except if this method fails to create a cache for a given workspace
+     * name).
+     * 
+     * @param workspaceName the name of the workspace
+     * @return the new cache that corresponds to the workspace name
+     */
+    @GuardedBy( "writeLock" )
+    protected Cache<UUID, MapNode> createNewCache( CacheFactory<UUID, MapNode> cacheFactory, String repositoryName ) {
+        assert repositoryName != null;
+        if (cacheFactory == null) return null;
+
+        // Try to create the cache using the workspace name as the configuration ...
+        try {
+            return cacheFactory.createCache(repositoryName);
+        } catch (ConfigurationException error) {
+            // The workspace name is probably not the name of a configuration ...
+            I18n msg = JBossCacheConnectorI18n.workspaceNameWasNotValidConfiguration;
+            Logger.getLogger(getClass()).debug(msg.text(repositoryName, error.getMessage()));
         }
 
-        return new JBossCacheConnection(this, this.workspaces);
+        if (this.cacheConfigurationName != null) {
+            // Try to create the cache using the default configuration name ...
+            try {
+                return cacheFactory.createCache(getCacheConfigurationName());
+            } catch (ConfigurationException error) {
+                // The default configuration name is not valid ...
+                if (this.repositoryNamesForConfigurationNameProblems.add(repositoryName)) {
+                    // Log this problem only the first time ...
+                    I18n msg = JBossCacheConnectorI18n.defaultCacheFactoryConfigurationNameWasNotValidConfiguration;
+                    Logger.getLogger(getClass()).debug(msg.text(repositoryName));
+                }
+            }
+        }
+
+        // Just create a new cache with the default configuration ...
+        return cacheFactory.createCache();
     }
 
+    
     /**
      * @return repositoryContext
      */
-    protected RepositoryContext getRepositoryContext() {
+    public RepositoryContext getRepositoryContext() {
         return repositoryContext;
     }
 

Deleted: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheWorkspaces.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheWorkspaces.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheWorkspaces.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -1,297 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of 
- * individual contributors.
- *
- * Unless otherwise indicated, all code in JBoss DNA is licensed
- * to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- * 
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.connector.jbosscache;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-import javax.naming.Context;
-import net.jcip.annotations.GuardedBy;
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.cache.Cache;
-import org.jboss.cache.CacheFactory;
-import org.jboss.cache.config.ConfigurationException;
-import org.jboss.dna.common.i18n.I18n;
-import org.jboss.dna.common.util.Logger;
-import org.jboss.dna.graph.connector.RepositorySourceException;
-import org.jboss.dna.graph.property.Name;
-
-/**
- * This class represents a set of workspaces used by the {@link JBossCacheSource JBoss Cache connector}.
- */
- at ThreadSafe
-public class JBossCacheWorkspaces {
-
-    private final String sourceName;
-    private final ConcurrentHashMap<String, Cache<Name, Object>> caches = new ConcurrentHashMap<String, Cache<Name, Object>>();
-    private final Set<String> initialNames;
-    private final CacheFactory<Name, Object> cacheFactory;
-    private final String defaultCacheFactoryConfigurationName;
-    private final Context jndi;
-    private final Set<String> workspaceNamesForJndiClassCastProblems = new HashSet<String>();
-    private final Set<String> workspaceNamesForConfigurationNameProblems = new HashSet<String>();
-    private final Lock writeLock = new ReentrantLock();
-
-    /**
-     * Create a new instance of the workspace and cache manager for the JBoss Cache connector.
-     * 
-     * @param sourceName the name of the source that uses this object; may not be null
-     * @param cacheFactory the factory that should be used to create new caches; may not be null
-     * @param defaultCacheFactoryConfigurationName the name of the configuration that is supplied to the {@link CacheFactory cache
-     *        factory} to {@link CacheFactory#createCache(String) create the new cache} if the workspace name does not correspond
-     *        to a configuration; may be null
-     * @param initialNames the initial names for the workspaces; may be null or empty
-     * @param jndiContext the JNDI context that should be used, or null if JNDI should not be used at all
-     */
-    public JBossCacheWorkspaces( String sourceName,
-                                 CacheFactory<Name, Object> cacheFactory,
-                                 String defaultCacheFactoryConfigurationName,
-                                 Set<String> initialNames,
-                                 Context jndiContext ) {
-        assert sourceName != null;
-        this.sourceName = sourceName;
-        if (initialNames == null) initialNames = Collections.emptySet();
-        this.initialNames = initialNames;
-        this.cacheFactory = cacheFactory;
-        this.defaultCacheFactoryConfigurationName = defaultCacheFactoryConfigurationName;
-        this.jndi = jndiContext;
-    }
-
-    /**
-     * Attempt to create a new workspace with the supplied name.
-     * 
-     * @param workspaceName the name of the new workspace, which may be a valid URI if the cache is to be found in JNDI
-     * @return the new workspace, or null if there is already a workspace with the name
-     */
-    public Cache<Name, Object> createWorkspace( String workspaceName ) {
-        try {
-            writeLock.lock();
-            // First, see if there is already an existing cache ...
-            Cache<Name, Object> cache = caches.get(workspaceName);
-            if (cache != null) {
-                // There is already a workspace, so we can't create ...
-                return null;
-            }
-
-            // There isn't already a cache, but next check the list of initial names ...
-            if (initialNames.contains(workspaceName)) {
-                // The workspace already exists, but we just haven't accessed it yet
-                return null;
-            }
-
-            // Time to create a new cache. First see if we're supposed to use a cache already in JNDI ...
-            cache = findCacheInJndi(workspaceName);
-            if (cache == null) {
-                // Try to create one ...
-                cache = createNewCache(workspaceName);
-            }
-
-            if (cache != null) {
-                // Manage this cache ...
-                Cache<Name, Object> existing = caches.putIfAbsent(workspaceName, cache);
-                if (existing != null) cache = existing;
-            }
-            return cache; // may still be null if we couldn't create a new cache
-
-        } finally {
-            writeLock.unlock();
-        }
-    }
-
-    /**
-     * Get the cache that corresponds to the supplied workspace name, and optionally create a new cache if no such cache already
-     * exists. This method first checks for {@link Cache} instances previously found for the same workspace name. If no cache is
-     * found, this method then checks whether the supplied workspace name is a valid URI, and if so the method looks for a
-     * {@link Cache} instance in JNDI at that URI. If none is found (or the name is not a valid URI), this method then creates a
-     * new {@link Cache} instance using the {@link CacheFactory} supplied in the constructor.
-     * 
-     * @param workspaceName the name of the workspace, which may be a valid URI if the cache is to be found in JNDI
-     * @param createIfMissing true if the cache should be created if no such cache already exists
-     * @return the cache that corresponds to the workspace with the supplied name, or null if there is no cache for that workspace
-     *         (and one could not be or was not created)
-     */
-    public Cache<Name, Object> getWorkspace( String workspaceName,
-                                             boolean createIfMissing ) {
-        // First, see if there is already an existing cache ...
-        Cache<Name, Object> cache = caches.get(workspaceName);
-        if (cache != null) return cache;
-
-        try {
-            writeLock.lock();
-            // Ensure one didn't get created while we waited for the lock ...
-            cache = caches.get(workspaceName);
-            if (cache != null) return cache;
-
-            // We've not yet come across the cache for the workspace.
-
-            // Check whether the workspace name was one of the initial set of names...
-            if (this.initialNames.contains(workspaceName)) {
-                // This workspace/cache was one of those defined at startup to be available,
-                // so we really don't consider this to be "creating a new cache"; it's just the first time we've used it
-                // and we're lazily finding the instances. So, just mark 'createIfMissing' to true and continue ...
-                createIfMissing = true;
-            }
-
-            if (!createIfMissing) return null;
-
-            // First see if we can find a cache in JNDI ...
-            cache = findCacheInJndi(workspaceName);
-
-            if (cache == null) {
-                // Try to create one ...
-                cache = createNewCache(workspaceName);
-            }
-
-            if (cache != null) {
-                Cache<Name, Object> existing = caches.putIfAbsent(workspaceName, cache);
-                if (existing != null) cache = existing;
-            }
-            return cache; // may still be null if we couldn't create a new cache
-        } finally {
-            writeLock.unlock();
-        }
-    }
-
-    /**
-     * Attempt to find an existing {@link Cache} object in JNDI, using the supplied workspace name as the JNDI name.
-     * 
-     * @param workspaceName the name of the workspace
-     * @return the cache found in JNDI that corresponds to the workspace name
-     */
-    @SuppressWarnings( "unchecked" )
-    @GuardedBy( "writeLock" )
-    protected Cache<Name, Object> findCacheInJndi( String workspaceName ) {
-        assert workspaceName != null;
-        if (jndi == null) return null;
-
-        // Try to look up the cache instance in JDNI ...
-        workspaceName = workspaceName.trim();
-        if (workspaceName.length() != 0) {
-            try {
-                new URI(workspaceName.trim());
-                Object object = null;
-                try {
-                    object = jndi.lookup(workspaceName);
-                    if (object != null && object instanceof Cache) {
-                        return (Cache<Name, Object>)object;
-                    }
-                } catch (ClassCastException err) {
-                    // The object found in JNDI was not a JBoss Cache instance ...
-                    if (this.workspaceNamesForJndiClassCastProblems.add(workspaceName)) {
-                        // Log this problem only the first time ...
-                        String className = object != null ? object.getClass().getName() : "null";
-                        I18n msg = JBossCacheConnectorI18n.objectFoundInJndiWasNotCache;
-                        Logger.getLogger(getClass()).warn(msg, workspaceName, sourceName, className);
-                    }
-                } catch (Throwable error) {
-                    // try loading
-                    if (error instanceof RuntimeException) throw (RuntimeException)error;
-                    throw new RepositorySourceException(sourceName, error);
-                }
-
-            } catch (URISyntaxException err) {
-                // Not a valid URI, so just continue ...
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Method that is responsible for attempting to create a new cache given the supplied workspace name. Note that this is
-     * probably called at most once for each workspace name (except if this method fails to create a cache for a given workspace
-     * name).
-     * 
-     * @param workspaceName the name of the workspace
-     * @return the new cache that corresponds to the workspace name
-     */
-    @GuardedBy( "writeLock" )
-    protected Cache<Name, Object> createNewCache( String workspaceName ) {
-        assert workspaceName != null;
-        if (this.cacheFactory == null) return null;
-
-        // Try to create the cache using the workspace name as the configuration ...
-        try {
-            return this.cacheFactory.createCache(workspaceName);
-        } catch (ConfigurationException error) {
-            // The workspace name is probably not the name of a configuration ...
-            I18n msg = JBossCacheConnectorI18n.workspaceNameWasNotValidConfiguration;
-            Logger.getLogger(getClass()).debug(msg.text(workspaceName, error.getMessage()));
-        }
-
-        if (this.defaultCacheFactoryConfigurationName != null) {
-            // Try to create the cache using the default configuration name ...
-            try {
-                return this.cacheFactory.createCache(this.defaultCacheFactoryConfigurationName);
-            } catch (ConfigurationException error) {
-                // The default configuration name is not valid ...
-                if (this.workspaceNamesForConfigurationNameProblems.add(workspaceName)) {
-                    // Log this problem only the first time ...
-                    I18n msg = JBossCacheConnectorI18n.defaultCacheFactoryConfigurationNameWasNotValidConfiguration;
-                    Logger.getLogger(getClass()).debug(msg.text(workspaceName));
-                }
-            }
-        }
-
-        // Just create a new cache with the default configuration ...
-        return this.cacheFactory.createCache();
-    }
-
-    /**
-     * Return an immutable set of names for the currently available workspaces.
-     * 
-     * @return the immutable set of workspace names; never null
-     */
-    public Set<String> getWorkspaceNames() {
-        Set<String> names = new HashSet<String>();
-        if (!initialNames.isEmpty()) names.addAll(initialNames);
-        names.addAll(caches.keySet());
-        return Collections.unmodifiableSet(names);
-    }
-
-    /**
-     * Remove the cache that corresponds to the supplied workspace name as no longer being available. This will remove the cache
-     * even if the workspace name is one of the "initial names" provided to this object's constructor.
-     * 
-     * @param workspaceName the name of the existing workspace that is to be removed
-     * @return true if there was an existing workspace that was removed by this call, or false if there was no workspace with the
-     *         supplied name
-     */
-    public boolean removeWorkspace( String workspaceName ) {
-        try {
-            writeLock.lock();
-
-            // Remove this from both the cache and initialNames ...
-            boolean removed = initialNames.remove(workspaceName);
-            if (caches.remove(workspaceName) != null) removed = true;
-            return removed;
-        } finally {
-            writeLock.unlock();
-        }
-    }
-}

Deleted: trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessorTest.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessorTest.java	2009-06-24 22:14:12 UTC (rev 1064)
+++ trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessorTest.java	2009-06-27 02:54:06 UTC (rev 1065)
@@ -1,120 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership.  Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of 
- * individual contributors. 
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.connector.jbosscache;
-
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
-import java.util.HashSet;
-import java.util.Set;
-import javax.naming.Context;
-import org.jboss.cache.CacheFactory;
-import org.jboss.cache.DefaultCacheFactory;
-import org.jboss.cache.Fqn;
-import org.jboss.dna.graph.DnaLexicon;
-import org.jboss.dna.graph.ExecutionContext;
-import org.jboss.dna.graph.property.Name;
-import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.PathFactory;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoAnnotations.Mock;
-
-/**
- * @author Randall Hauch
- */
-public class JBossCacheRequestProcessorTest {
-
-    private JBossCacheRequestProcessor processor;
-    private JBossCacheWorkspaces workspaces;
-    private Set<String> initialWorkspaceNames;
-    private String defaultWorkspaceName;
-    private String defaultConfigName;
-    private CacheFactory<Name, Object> cacheFactory;
-    private ExecutionContext context;
-    private PathFactory pathFactory;
-    @Mock
-    private Context jndi;
-
-    @Before
-    public void beforeEach() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        context = new ExecutionContext();
-        context.getNamespaceRegistry().register(DnaLexicon.Namespace.PREFIX, DnaLexicon.Namespace.URI);
-        context.getNamespaceRegistry().register(JBossCacheLexicon.Namespace.PREFIX, JBossCacheLexicon.Namespace.URI);
-
-        cacheFactory = new DefaultCacheFactory<Name, Object>();
-        defaultConfigName = null;
-        initialWorkspaceNames = new HashSet<String>();
-        initialWorkspaceNames.add("workspace1");
-        initialWorkspaceNames.add("workspace2");
-        defaultWorkspaceName = initialWorkspaceNames.iterator().next();
-        workspaces = new JBossCacheWorkspaces("source", cacheFactory, defaultConfigName, initialWorkspaceNames, jndi);
-        processor = new JBossCacheRequestProcessor("source", context, null, workspaces, defaultWorkspaceName, true);
-
-        pathFactory = context.getValueFactories().getPathFactory();
-    }
-
-    @Test
-    public void shouldCreateFullyQualifiedNodeOfPathSegmentsFromPath() {
-        Path path = pathFactory.create("/a/b/c/d");
-        Fqn<?> fqn = processor.getFullyQualifiedName(path);
-        assertThat(fqn.size(), is(4));
-        assertThat(fqn.isRoot(), is(false));
-        for (int i = 0; i != path.size(); ++i) {
-            assertThat((Path.Segment)fqn.get(i), is(path.getSegment(i)));
-        }
-    }
-
-    @Test
-    public void shouldCreateFullyQualifiedNodeOfPathSegmentsFromRootPath() {
-        Path path = pathFactory.createRootPath();
-        Fqn<?> fqn = processor.getFullyQualifiedName(path);
-        assertThat(fqn.size(), is(0));
-        assertThat(fqn.isRoot(), is(true));
-    }
-
-    @Test
-    public void shouldCreateFullyQualifiedNodeFromPathSegment() {
-        Path.Segment segment = pathFactory.createSegment("a");
-        Fqn<?> fqn = processor.getFullyQualifiedName(segment);
-        assertThat(fqn.size(), is(1));
-        assertThat(fqn.isRoot(), is(false));
-        assertThat((Path.Segment)fqn.get(0), is(segment));
-    }
-
-    @Test
-    public void shouldCreatePathFromFullyQualifiedNode() {
-        Path path = pathFactory.create("/a/b/c/d");
-        Fqn<Path.Segment> fqn = processor.getFullyQualifiedName(path);
-        assertThat(processor.getPath(pathFactory, fqn), is(path));
-    }
-
-    @Test
-    public void shouldCreateRootPathFromRootFullyQualifiedNode() {
-        Path path = pathFactory.createRootPath();
-        Fqn<Path.Segment> fqn = processor.getFullyQualifiedName(path);
-        assertThat(processor.getPath(pathFactory, fqn), is(path));
-    }
-}




More information about the dna-commits mailing list