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

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Thu Jan 15 21:37:49 EST 2009


Author: rhauch
Date: 2009-01-15 21:37:49 -0500 (Thu, 15 Jan 2009)
New Revision: 710

Added:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/
   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/InMemoryRepository.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/InMemoryRepositorySource.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/package-info.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryConnectorReadingTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryConnectorWritingTest.java
   trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryTest.java
Removed:
   trunk/extensions/dna-connector-inmemory/
Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
   trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
   trunk/docs/examples/gettingstarted/pom.xml
   trunk/docs/examples/gettingstarted/repositories/pom.xml
   trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
   trunk/docs/examples/gettingstarted/repositories/src/main/resources/configRepository.xml
   trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java
   trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml
   trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml
   trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml
   trunk/docs/reference/src/main/docbook/en-US/custom.dtd
   trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties
   trunk/pom.xml
Log:
DNA-272 Move the In-Memory connector into "dna-graph"

The In-Memory connector was moved from a separate extension project into the dna-graph project.  This change did cause the package names to differ slightly (the addition of the 'graph' intermediate package), and so this affected the repository example and the documentation.

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java	2009-01-16 02:37:49 UTC (rev 710)
@@ -83,6 +83,12 @@
     public static I18n errorImportingContent;
     public static I18n unableToFindRepositorySourceWithName;
 
+    /* In-Memory Connector */
+    public static I18n inMemoryConnectorName;
+    public static I18n inMemoryNodeDoesNotExist;
+    public static I18n errorSerializingInMemoryCachePolicyInSource;
+    public static I18n inMemoryConnectorRequestsMustHavePathOrUuid;
+
     static {
         try {
             I18n.initialize(GraphI18n.class);

Added: 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	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryNode.java	2009-01-16 02:37:49 UTC (rev 710)
@@ -0,0 +1,171 @@
+/*
+ * 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.LinkedList;
+import java.util.List;
+import java.util.Map;
+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 List<InMemoryNode> children = new LinkedList<InMemoryNode>();
+
+    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
+     */
+    protected List<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();
+    }
+}

Added: 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	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java	2009-01-16 02:37:49 UTC (rev 710)
@@ -0,0 +1,583 @@
+/*
+ * 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.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.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.Location;
+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.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.Path.Segment;
+import org.jboss.dna.graph.property.basic.RootPath;
+import org.jboss.dna.graph.request.CopyBranchRequest;
+import org.jboss.dna.graph.request.CreateNodeRequest;
+import org.jboss.dna.graph.request.DeleteBranchRequest;
+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.processor.RequestProcessor;
+
+/**
+ * @author Randall Hauch
+ */
+ at NotThreadSafe
+public class InMemoryRepository {
+
+    protected final ReadWriteLock lock = new ReentrantReadWriteLock();
+    private final String name;
+    private final UUID rootNodeUuid;
+    private final Map<UUID, InMemoryNode> nodesByUuid = new HashMap<UUID, InMemoryNode>();
+
+    public InMemoryRepository( String name,
+                               UUID rootNodeUUID ) {
+        CheckArg.isNotNull(rootNodeUUID, "rootNodeUUID");
+        CheckArg.isNotEmpty(name, "name");
+        this.name = name;
+        this.rootNodeUuid = rootNodeUUID;
+        // Create the root node ...
+        InMemoryNode root = new InMemoryNode(rootNodeUUID);
+        nodesByUuid.put(root.getUuid(), root);
+    }
+
+    /**
+     * @return lock
+     */
+    public ReadWriteLock getLock() {
+        return lock;
+    }
+
+    /**
+     * @return name
+     */
+    public String getName() {
+        return name;
+    }
+
+    public InMemoryNode getRoot() {
+        return nodesByUuid.get(this.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;
+    }
+
+    /**
+     * 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 UUID generateUuid() {
+        return UUID.randomUUID();
+    }
+
+    public void removeNode( ExecutionContext context,
+                            InMemoryNode node ) {
+        assert context != null;
+        assert node != null;
+        assert getRoot().equals(node) != true;
+        InMemoryNode parent = node.getParent();
+        assert parent != null;
+        parent.getChildren().remove(node);
+        correctSameNameSiblingIndexes(context, parent, node.getName().getName());
+        removeUuidReference(node);
+    }
+
+    protected void removeUuidReference( InMemoryNode node ) {
+        nodesByUuid.remove(node.getUuid());
+        for (InMemoryNode 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 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 = generateUuid();
+        InMemoryNode node = new InMemoryNode(uuid);
+        nodesByUuid.put(node.getUuid(), node);
+        node.setParent(parentNode);
+        Path.Segment newName = context.getValueFactories().getPathFactory().createSegment(name);
+        node.setName(newName);
+        parentNode.getChildren().add(node);
+        correctSameNameSiblingIndexes(context, parentNode, name);
+        return node;
+    }
+
+    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.NO_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;
+        }
+    }
+
+    /**
+     * 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 #getRoot() root}
+     * @param newParent the new parent; may not be the {@link #getRoot() root}
+     */
+    public void moveNode( ExecutionContext context,
+                          InMemoryNode node,
+                          InMemoryNode newParent ) {
+        assert context != null;
+        assert newParent != null;
+        assert node != null;
+        assert getRoot().equals(newParent) != true;
+        assert getRoot().equals(node) != true;
+        InMemoryNode oldParent = node.getParent();
+        if (oldParent != null) {
+            if (oldParent.equals(newParent)) return;
+            boolean removed = oldParent.getChildren().remove(node);
+            assert removed == true;
+            node.setParent(null);
+            correctSameNameSiblingIndexes(context, oldParent, node.getName().getName());
+        }
+        node.setParent(newParent);
+        newParent.getChildren().add(node);
+        correctSameNameSiblingIndexes(context, newParent, node.getName().getName());
+    }
+
+    /**
+     * 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
+     * @param original
+     * @param newParent
+     * @param recursive
+     * @param oldToNewUuids the map of UUIDs of nodes in the new subgraph keyed by the UUIDs of nodes in the original; may not be
+     *        null
+     * @return the new node, which is the top of the new subgraph
+     */
+    public InMemoryNode copyNode( ExecutionContext context,
+                                  InMemoryNode original,
+                                  InMemoryNode newParent,
+                                  boolean recursive,
+                                  Map<UUID, UUID> oldToNewUuids ) {
+        assert context != null;
+        assert original != null;
+        assert newParent != null;
+        assert oldToNewUuids != null;
+
+        // Get or create the new node ...
+        InMemoryNode copy = createNode(context, newParent, original.getName().getName(), 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, copy, true, oldToNewUuids);
+            }
+        }
+
+        // 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 = nodesByUuid.get(oldToNew.getKey());
+            InMemoryNode newNode = nodesByUuid.get(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;
+    }
+
+    /**
+     * Get a request processor given the supplied environment and source name.
+     * 
+     * @param context the environment in which the commands are to be executed
+     * @param sourceName the name of the repository source
+     * @return the request processor; never null
+     */
+    /*package*/RequestProcessor getRequestProcessor( ExecutionContext context,
+                                                      String sourceName ) {
+        return new Processor(context, sourceName);
+    }
+
+    protected class Processor extends RequestProcessor {
+        private final PathFactory pathFactory;
+        private final PropertyFactory propertyFactory;
+
+        protected Processor( ExecutionContext context,
+                             String sourceName ) {
+            super(sourceName, context);
+            pathFactory = context.getValueFactories().getPathFactory();
+            propertyFactory = context.getPropertyFactory();
+        }
+
+        @Override
+        public void process( ReadAllChildrenRequest request ) {
+            InMemoryNode node = getTargetNode(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 ) {
+            InMemoryNode node = getTargetNode(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 ) {
+            InMemoryNode node = getTargetNode(request, request.from());
+            if (node == null) return;
+            // Look up the new parent, which must exist ...
+            Path newParentPath = request.into().getPath();
+            InMemoryNode newParent = getNode(newParentPath);
+            InMemoryNode newNode = copyNode(getExecutionContext(), node, newParent, true, new HashMap<UUID, UUID>());
+            Path newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, newNode.getName());
+            Location oldLocation = getActualLocation(request.from().getPath(), node);
+            Location newLocation = new Location(newPath, newNode.getUuid());
+            request.setActualLocations(oldLocation, newLocation);
+        }
+
+        @Override
+        public void process( CreateNodeRequest request ) {
+            Path parent = request.under().getPath();
+            CheckArg.isNotNull(parent, "request.under().getPath()");
+            InMemoryNode node = null;
+            // Look up the parent node, which must exist ...
+            InMemoryNode parentNode = getNode(parent);
+            if (parentNode == null) {
+                Path lowestExisting = getLowestExistingPath(parent);
+                request.setError(new PathNotFoundException(request.under(), lowestExisting,
+                                                           GraphI18n.inMemoryNodeDoesNotExist.text(parent)));
+            }
+            UUID uuid = null;
+            for (Property property : request.properties()) {
+                if (property.getName().equals(DnaLexicon.UUID)) {
+                    uuid = getExecutionContext().getValueFactories().getUuidFactory().create(property.getValues().next());
+                    break;
+                }
+            }
+            node = createNode(getExecutionContext(), parentNode, request.named(), uuid);
+            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);
+        }
+
+        @Override
+        public void process( DeleteBranchRequest request ) {
+            InMemoryNode node = getTargetNode(request, request.at());
+            if (node == null) return;
+            removeNode(getExecutionContext(), node);
+            Location actualLocation = getActualLocation(request.at().getPath(), node);
+            request.setActualLocationOfNode(actualLocation);
+        }
+
+        @Override
+        public void process( MoveBranchRequest request ) {
+            InMemoryNode node = getTargetNode(request, request.from());
+            if (node == null) return;
+            // Look up the new parent, which must exist ...
+            Path newPath = request.into().getPath();
+            Path newParentPath = newPath.getParent();
+            InMemoryNode newParent = getNode(newParentPath);
+            node.setParent(newParent);
+            newPath = getExecutionContext().getValueFactories().getPathFactory().create(newParentPath, node.getName());
+            Location oldLocation = getActualLocation(request.from().getPath(), node);
+            Location newLocation = new Location(newPath, node.getUuid());
+            request.setActualLocations(oldLocation, newLocation);
+        }
+
+        @Override
+        public void process( UpdatePropertiesRequest request ) {
+            InMemoryNode node = getTargetNode(request, request.on());
+            if (node == null) return;
+            // Now set (or remove) 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(request.on().getPath(), node);
+            request.setActualLocationOfNode(actualLocation);
+        }
+
+        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 new Location(path, node.getUuid());
+        }
+
+        protected InMemoryNode getTargetNode( Request request,
+                                              Location location ) {
+            // Check first for the UUID ...
+            InMemoryNode node = null;
+            UUID uuid = location.getUuid();
+            if (uuid != null) {
+                node = InMemoryRepository.this.getNode(uuid);
+            }
+            Path path = null;
+            if (node == null) {
+                // Look up the node with the supplied path ...
+                path = location.getPath();
+                if (path != null) {
+                    node = InMemoryRepository.this.getNode(path);
+                }
+            }
+            if (node == 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 = 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/inmemory/InMemoryRepositoryConnection.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryConnection.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryConnection.java	2009-01-16 02:37:49 UTC (rev 710)
@@ -0,0 +1,158 @@
+/*
+ * 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.connector.RepositorySourceListener;
+import org.jboss.dna.graph.request.Request;
+import org.jboss.dna.graph.request.processor.RequestProcessor;
+
+/**
+ * @author Randall Hauch
+ */
+public class InMemoryRepositoryConnection implements RepositoryConnection {
+
+    protected static final RepositorySourceListener NO_OP_LISTENER = new RepositorySourceListener() {
+
+        /**
+         * {@inheritDoc}
+         */
+        public void notify( String sourceName,
+                            Object... events ) {
+            // do nothing
+        }
+    };
+
+    private final InMemoryRepositorySource source;
+    private final InMemoryRepository content;
+    private RepositorySourceListener listener = NO_OP_LISTENER;
+
+    InMemoryRepositoryConnection( InMemoryRepositorySource source,
+                                  InMemoryRepository content ) {
+        assert source != null;
+        assert content != null;
+        this.source = source;
+        this.content = content;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getSourceName() {
+        return source.getName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public CachePolicy getDefaultCachePolicy() {
+        return source.getDefaultCachePolicy();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public XAResource getXAResource() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean ping( long time,
+                         TimeUnit unit ) {
+        this.content.getRoot();
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setListener( RepositorySourceListener listener ) {
+        this.listener = listener != null ? listener : NO_OP_LISTENER;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() {
+        // do nothing
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @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 = this.content.getRequestProcessor(context, this.getSourceName());
+
+        Lock lock = request.isReadOnly() ? content.getLock().readLock() : content.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());
+        }
+    }
+
+    protected InMemoryRepository getContent() {
+        return content;
+    }
+
+    /**
+     * @return listener
+     */
+    protected RepositorySourceListener getListener() {
+        return this.listener;
+    }
+
+}

Added: 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	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositorySource.java	2009-01-16 02:37:49 UTC (rev 710)
@@ -0,0 +1,325 @@
+/*
+ * 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.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.naming.BinaryRefAddr;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.ObjectFactory;
+import net.jcip.annotations.GuardedBy;
+import org.jboss.dna.common.i18n.I18n;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.cache.CachePolicy;
+import org.jboss.dna.graph.connector.RepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryContext;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.RepositorySourceCapabilities;
+import org.jboss.dna.graph.connector.RepositorySourceException;
+
+/**
+ * @author Randall Hauch
+ */
+public class InMemoryRepositorySource implements RepositorySource, ObjectFactory {
+
+    /**
+     * The initial version is 1
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * The default limit is {@value} for retrying {@link RepositoryConnection connection} calls to the underlying source.
+     */
+    public static final int DEFAULT_RETRY_LIMIT = 0;
+
+    protected static final RepositorySourceCapabilities CAPABILITIES = new RepositorySourceCapabilities(true, true);
+
+    protected static final String ROOT_NODE_UUID = "rootNodeUuid";
+    protected static final String SOURCE_NAME = "sourceName";
+    protected static final String DEFAULT_CACHE_POLICY = "defaultCachePolicy";
+    protected static final String JNDI_NAME = "jndiName";
+    protected static final String RETRY_LIMIT = "retryLimit";
+
+    @GuardedBy( "sourcesLock" )
+    private String name;
+    @GuardedBy( "this" )
+    private String jndiName;
+    private UUID rootNodeUuid = UUID.randomUUID();
+    private CachePolicy defaultCachePolicy;
+    private final AtomicInteger retryLimit = new AtomicInteger(DEFAULT_RETRY_LIMIT);
+    private transient InMemoryRepository repository;
+    private transient RepositoryContext repositoryContext;
+
+    /**
+     * Create a repository source instance.
+     */
+    public InMemoryRepositorySource() {
+        super();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositorySource#initialize(org.jboss.dna.graph.connector.RepositoryContext)
+     */
+    public void initialize( RepositoryContext context ) throws RepositorySourceException {
+        this.repositoryContext = context;
+    }
+
+    /**
+     * @return repositoryContext
+     */
+    public RepositoryContext getRepositoryContext() {
+        return repositoryContext;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositorySource#getRetryLimit()
+     */
+    public int getRetryLimit() {
+        return retryLimit.get();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositorySource#setRetryLimit(int)
+     */
+    public void setRetryLimit( int limit ) {
+        retryLimit.set(limit < 0 ? 0 : limit);
+    }
+
+    /**
+     * Get the default cache policy for this source, or null if the global default cache policy should be used
+     * 
+     * @return the default cache policy, or null if this source has no explicit default cache policy
+     */
+    public CachePolicy getDefaultCachePolicy() {
+        return defaultCachePolicy;
+    }
+
+    /**
+     * @param defaultCachePolicy Sets defaultCachePolicy to the specified value.
+     */
+    public void setDefaultCachePolicy( CachePolicy defaultCachePolicy ) {
+        this.defaultCachePolicy = defaultCachePolicy;
+    }
+
+    /**
+     * @return rootNodeUuid
+     */
+    public UUID getRootNodeUuid() {
+        return this.rootNodeUuid;
+    }
+
+    /**
+     * @param rootNodeUuid Sets rootNodeUuid to the specified value.
+     */
+    public void setRootNodeUuid( UUID rootNodeUuid ) {
+        this.rootNodeUuid = rootNodeUuid != null ? rootNodeUuid : UUID.randomUUID();
+    }
+
+    /**
+     * If you use this to set a JNDI name, this source will be bound to that name using the default {@link InitialContext}. You
+     * can also do this manually if you have additional requirements.
+     * 
+     * @param name the JNDI name
+     * @throws NamingException if there is a problem registering this object
+     * @see #getJndiName()
+     */
+    public void setJndiName( String name ) throws NamingException {
+        setJndiName(name, null);
+    }
+
+    /**
+     * Register this source in JNDI under the supplied name using the supplied context. to set a JNDI name, this source will be
+     * bound to that name using the default {@link InitialContext}. You can also do this manually if you have additional
+     * requirements.
+     * 
+     * @param name the JNDI name, or null if this object is to no longer be registered
+     * @param context the JNDI context, or null if the {@link InitialContext} should be used
+     * @throws NamingException if there is a problem registering this object
+     * @see #getJndiName()
+     */
+    public synchronized void setJndiName( String name,
+                                          Context context ) throws NamingException {
+        CheckArg.isNotNull(name, "name");
+        if (context == null) context = new InitialContext();
+
+        // First register in JNDI under the new name ...
+        if (name != null) {
+            context.bind(name, this);
+        }
+        // Second, unregister from JNDI if there is already a name ...
+        if (jndiName != null && !jndiName.equals(name)) {
+            context.unbind(jndiName);
+        }
+        // Record the new name ...
+        this.jndiName = name;
+    }
+
+    /**
+     * Gets the JNDI name this source is bound to. Only valid if you used setJNDIName to bind it.
+     * 
+     * @return the JNDI name, or null if it is not bound in JNDI
+     * @see #setJndiName(String)
+     */
+    public synchronized String getJndiName() {
+        return jndiName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * @param name Sets name to the specified value.
+     */
+    public void setName( String name ) {
+        this.name = name;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositorySource#getConnection()
+     */
+    public RepositoryConnection getConnection() throws RepositorySourceException {
+        if (repository == null) {
+            repository = new InMemoryRepository(name, rootNodeUuid);
+        }
+        return new InMemoryRepositoryConnection(this, repository);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized Reference getReference() {
+        String className = getClass().getName();
+        String factoryClassName = this.getClass().getName();
+        Reference ref = new Reference(className, factoryClassName, null);
+
+        if (getName() != null) {
+            ref.add(new StringRefAddr(SOURCE_NAME, getName()));
+        }
+        if (getRootNodeUuid() != null) {
+            ref.add(new StringRefAddr(ROOT_NODE_UUID, getRootNodeUuid().toString()));
+        }
+        if (getJndiName() != null) {
+            ref.add(new StringRefAddr(JNDI_NAME, getJndiName()));
+        }
+        if (getDefaultCachePolicy() != null) {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            CachePolicy policy = getDefaultCachePolicy();
+            try {
+                ObjectOutputStream oos = new ObjectOutputStream(baos);
+                oos.writeObject(policy);
+                ref.add(new BinaryRefAddr(DEFAULT_CACHE_POLICY, baos.toByteArray()));
+            } catch (IOException e) {
+                I18n msg = GraphI18n.errorSerializingInMemoryCachePolicyInSource;
+                throw new RepositorySourceException(getName(), msg.text(policy.getClass().getName(), getName()), e);
+            }
+        }
+        ref.add(new StringRefAddr(RETRY_LIMIT, Integer.toString(getRetryLimit())));
+        return ref;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getObjectInstance( Object obj,
+                                     javax.naming.Name name,
+                                     Context nameCtx,
+                                     Hashtable<?, ?> environment ) throws Exception {
+        if (obj instanceof Reference) {
+            Map<String, Object> values = new HashMap<String, Object>();
+            Reference ref = (Reference)obj;
+            Enumeration<?> en = ref.getAll();
+            while (en.hasMoreElements()) {
+                RefAddr subref = (RefAddr)en.nextElement();
+                if (subref instanceof StringRefAddr) {
+                    String key = subref.getType();
+                    Object value = subref.getContent();
+                    if (value != null) values.put(key, value.toString());
+                } else if (subref instanceof BinaryRefAddr) {
+                    String key = subref.getType();
+                    Object value = subref.getContent();
+                    if (value instanceof byte[]) {
+                        // Deserialize ...
+                        ByteArrayInputStream bais = new ByteArrayInputStream((byte[])value);
+                        ObjectInputStream ois = new ObjectInputStream(bais);
+                        value = ois.readObject();
+                        values.put(key, value);
+                    }
+                }
+            }
+            String sourceName = (String)values.get(SOURCE_NAME);
+            String rootNodeUuidString = (String)values.get(ROOT_NODE_UUID);
+            String jndiName = (String)values.get(JNDI_NAME);
+            Object defaultCachePolicy = values.get(DEFAULT_CACHE_POLICY);
+            String retryLimit = (String)values.get(RETRY_LIMIT);
+
+            // Create the source instance ...
+            InMemoryRepositorySource source = new InMemoryRepositorySource();
+            if (sourceName != null) source.setName(sourceName);
+            if (rootNodeUuidString != null) source.setRootNodeUuid(UUID.fromString(rootNodeUuidString));
+            if (jndiName != null) source.setJndiName(jndiName);
+            if (defaultCachePolicy instanceof CachePolicy) {
+                source.setDefaultCachePolicy((CachePolicy)defaultCachePolicy);
+            }
+            if (retryLimit != null) source.setRetryLimit(Integer.parseInt(retryLimit));
+            return source;
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.RepositorySource#getCapabilities()
+     */
+    public RepositorySourceCapabilities getCapabilities() {
+        return CAPABILITIES;
+    }
+}

Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/package-info.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/package-info.java	                        (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/package-info.java	2009-01-16 02:37:49 UTC (rev 710)
@@ -0,0 +1,31 @@
+/*
+ * 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 In-Memory Connector represents a {@link org.jboss.dna.graph.connector.RepositorySource connector} that maintains 
+ * a graph in transient in-process memory.  This connector is a good solution for a readable and writable repository source
+ * that is very lightweight and of small to moderate sizes.
+ */
+
+package org.jboss.dna.graph.connector.inmemory;
+

Modified: trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
===================================================================
--- trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties	2009-01-16 02:37:49 UTC (rev 710)
@@ -70,3 +70,8 @@
 errorImportingContent = Error importing {0} content from {1}
 unableToFindRepositorySourceWithName = Unable to find a repository source named "{0}"
 
+# In-memory connector
+inMemoryConnectorName = In-Memory Connector
+inMemoryNodeDoesNotExist = Could not find an existing node at {0}
+errorSerializingInMemoryCachePolicyInSource = Error serializing a {0} instance owned by the {1} In-Memory repository source
+inMemoryConnectorRequestsMustHavePathOrUuid = In-Memory connector can only process requests with a path and/or UUID

Added: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryConnectorReadingTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryConnectorReadingTest.java	                        (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryConnectorReadingTest.java	2009-01-16 02:37:49 UTC (rev 710)
@@ -0,0 +1,63 @@
+/*
+ * 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 org.jboss.dna.common.statistic.Stopwatch;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.test.ReadableConnectorTest;
+
+/**
+ * @author Randall Hauch
+ */
+public class InMemoryConnectorReadingTest extends ReadableConnectorTest {
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#setUpSource()
+     */
+    @Override
+    protected RepositorySource setUpSource() {
+        InMemoryRepositorySource source = new InMemoryRepositorySource();
+        source.setName("Test Repository");
+        return source;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#initializeContent(org.jboss.dna.graph.Graph)
+     */
+    @Override
+    protected void initializeContent( Graph graph ) {
+        String initialPath = "";
+        int depth = 4;
+        int numChildrenPerNode = 4;
+        int numPropertiesPerNode = 7;
+        Stopwatch sw = new Stopwatch();
+        boolean batch = true;
+        createSubgraph(graph, initialPath, depth, numChildrenPerNode, numPropertiesPerNode, batch, sw, System.out, null);
+    }
+}

Added: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryConnectorWritingTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryConnectorWritingTest.java	                        (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryConnectorWritingTest.java	2009-01-16 02:37:49 UTC (rev 710)
@@ -0,0 +1,56 @@
+/*
+ * 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 org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.test.WritableConnectorTest;
+
+/**
+ * @author Randall Hauch
+ */
+public class InMemoryConnectorWritingTest extends WritableConnectorTest {
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#setUpSource()
+     */
+    @Override
+    protected RepositorySource setUpSource() {
+        InMemoryRepositorySource source = new InMemoryRepositorySource();
+        source.setName("Test Repository");
+        return source;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.graph.connector.test.AbstractConnectorTest#initializeContent(org.jboss.dna.graph.Graph)
+     */
+    @Override
+    protected void initializeContent( Graph graph ) {
+    }
+
+}

Added: 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	                        (rev 0)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryTest.java	2009-01-16 02:37:49 UTC (rev 710)
@@ -0,0 +1,365 @@
+/*
+ * 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 static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.stub;
+import java.util.HashMap;
+import java.util.HashSet;
+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.PathFactory;
+import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.property.PropertyFactory;
+import org.jboss.dna.graph.property.ValueFactories;
+import org.jboss.dna.graph.property.ValueFactory;
+import org.jboss.dna.graph.property.basic.BasicNamespaceRegistry;
+import org.jboss.dna.graph.property.basic.BasicPropertyFactory;
+import org.jboss.dna.graph.property.basic.StandardValueFactories;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+
+/**
+ * @author Randall Hauch
+ */
+public class InMemoryRepositoryTest {
+
+    private InMemoryRepository repository;
+    private String name;
+    private UUID rootUuid;
+    private ValueFactories valueFactories;
+    private PathFactory pathFactory;
+    private NameFactory nameFactory;
+    private PropertyFactory propertyFactory;
+    @Mock
+    private ExecutionContext context;
+
+    @Before
+    public void beforeEach() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        valueFactories = new StandardValueFactories(new BasicNamespaceRegistry());
+        pathFactory = valueFactories.getPathFactory();
+        nameFactory = valueFactories.getNameFactory();
+        propertyFactory = new BasicPropertyFactory(valueFactories);
+        name = "Test repository";
+        rootUuid = UUID.randomUUID();
+        repository = new InMemoryRepository(name, rootUuid);
+        stub(context.getValueFactories()).toReturn(valueFactories);
+        stub(context.getPropertyFactory()).toReturn(propertyFactory);
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowNullNameInConstructor() {
+        new InMemoryRepository(null, rootUuid);
+    }
+
+    @Test( expected = IllegalArgumentException.class )
+    public void shouldNotAllowBlankNameInConstructor() {
+        new InMemoryRepository("  \t  ", rootUuid);
+    }
+
+    @Test
+    public void shouldHaveLock() {
+        assertThat(repository.getLock(), is(notNullValue()));
+    }
+
+    @Test
+    public void shouldHaveRootNodeAfterInstantiating() {
+        assertThat(repository.getRoot(), is(notNullValue()));
+    }
+
+    @Test
+    public void shouldHaveNameAfterInstantiating() {
+        assertThat(repository.getName(), is(name));
+    }
+
+    @Test
+    public void shouldHaveRootNodeWithRootUuid() {
+        assertThat(repository.getRoot().getUuid(), is(rootUuid));
+    }
+
+    @Test
+    public void shouldGenerateUuids() {
+        Set<UUID> uuids = new HashSet<UUID>();
+        for (int i = 0; i != 100; ++i) {
+            assertThat(uuids.add(repository.generateUuid()), is(true));
+        }
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowRootToBeRemoved() {
+        repository.removeNode(context, repository.getRoot());
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowRootToBeMoved() {
+        InMemoryNode node = mock(InMemoryNode.class);
+        repository.moveNode(context, repository.getRoot(), node);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNodeToBeMovedUsingNullEnvironment() {
+        InMemoryNode node = mock(InMemoryNode.class);
+        InMemoryNode newParent = mock(InMemoryNode.class);
+        repository.moveNode(null, node, newParent);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullNodeToBeMoved() {
+        InMemoryNode newParent = mock(InMemoryNode.class);
+        repository.moveNode(context, null, newParent);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNodeToBeRemovedUsingNullEnvironment() {
+        InMemoryNode node = mock(InMemoryNode.class);
+        repository.removeNode(null, node);
+    }
+
+    @Test( expected = AssertionError.class )
+    public void shouldNotAllowNullNodeToBeRemoved() {
+        repository.removeNode(context, null);
+    }
+
+    @Test
+    public void shouldCreateNodesByPath() {
+        Name name_a = nameFactory.create("a");
+        InMemoryNode node_a = repository.createNode(context, repository.getRoot(), name_a, null);
+        assertThat(node_a, is(notNullValue()));
+        assertThat(node_a.getParent(), is(repository.getRoot()));
+        assertThat(node_a.getName().getName(), is(name_a));
+        assertThat(node_a.getName().hasIndex(), is(false));
+
+        Name name_b = nameFactory.create("b");
+        InMemoryNode node_b = repository.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 = repository.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(repository.getNodesByUuid().size(), is(4));
+        assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+        assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+        assertThat(repository.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
+        assertThat(repository.getNode(pathFactory.create("/a/b/c")), is(sameInstance(node_c)));
+    }
+
+    @Test
+    public void shouldNotFindNodesThatDoNotExist() {
+        InMemoryNode node_a = repository.createNode(context, repository.getRoot(), nameFactory.create("a"), null);
+        InMemoryNode node_b = repository.createNode(context, node_a, nameFactory.create("b"), null);
+        /*Node node_c =*/repository.createNode(context, node_b, nameFactory.create("c"), null);
+
+        assertThat(repository.getNodesByUuid().size(), is(4));
+        assertThat(repository.getNode(pathFactory.create("/a")), is(node_a));
+        assertThat(repository.getNode(pathFactory.create("/a/b")), is(node_b));
+        assertThat(repository.getNode(pathFactory.create("/a[1]")), is(node_a));
+        assertThat(repository.getNode(pathFactory.create("/a/b[1]")), is(node_b));
+        assertThat(repository.getNode(pathFactory.create("/a[1]/b[1]")), is(node_b));
+        assertThat(repository.getNode(pathFactory.create("/a[2]")), is(nullValue()));
+        assertThat(repository.getNode(pathFactory.create("/b[2]")), is(nullValue()));
+        assertThat(repository.getNode(pathFactory.create("/d")), is(nullValue()));
+    }
+
+    @Test
+    public void shouldCorrectlyManageIndexesOfSiblingsWithSameNames() {
+        Name name_a1 = nameFactory.create("a");
+        InMemoryNode node_a1 = repository.createNode(context, repository.getRoot(), name_a1, null);
+        assertThat(node_a1, is(notNullValue()));
+        assertThat(node_a1.getParent(), is(repository.getRoot()));
+        assertThat(node_a1.getName().getName(), is(name_a1));
+        assertThat(node_a1.getName().hasIndex(), is(false));
+
+        Name name_a2 = nameFactory.create("a");
+        InMemoryNode node_a2 = repository.createNode(context, repository.getRoot(), name_a2, null);
+        assertThat(node_a2, is(notNullValue()));
+        assertThat(node_a2.getParent(), is(repository.getRoot()));
+        assertThat(node_a2.getName().getName(), is(name_a2));
+        assertThat(node_a2.getName().hasIndex(), is(true));
+        assertThat(node_a2.getName().getIndex(), is(2));
+
+        // node 1 should now have an index ...
+        assertThat(node_a1.getName().getIndex(), is(1));
+
+        // Add another node without the same name ...
+        Name name_b = nameFactory.create("b");
+        InMemoryNode node_b = repository.createNode(context, repository.getRoot(), name_b, null);
+        assertThat(node_b, is(notNullValue()));
+        assertThat(node_b.getParent(), is(repository.getRoot()));
+        assertThat(node_b.getName().getName(), is(name_b));
+        assertThat(node_b.getName().hasIndex(), is(false));
+
+        // Add a third node with the same name ...
+        Name name_a3 = nameFactory.create("a");
+        InMemoryNode node_a3 = repository.createNode(context, repository.getRoot(), name_a3, null);
+        assertThat(node_a3, is(notNullValue()));
+        assertThat(node_a3.getParent(), is(repository.getRoot()));
+        assertThat(node_a3.getName().getName(), is(name_a3));
+        assertThat(node_a3.getName().hasIndex(), is(true));
+        assertThat(node_a3.getName().getIndex(), is(3));
+
+        // Check the number of children ...
+        assertThat(repository.getRoot().getChildren().size(), is(4));
+        assertThat(repository.getRoot().getChildren(), hasItems(node_a1, node_a2, node_b, node_a3));
+        assertThat(repository.getNodesByUuid().size(), is(5));
+        assertThat(repository.getNode(pathFactory.create("/a[1]")), is(sameInstance(node_a1)));
+        assertThat(repository.getNode(pathFactory.create("/a[2]")), is(sameInstance(node_a2)));
+        assertThat(repository.getNode(pathFactory.create("/a[3]")), is(sameInstance(node_a3)));
+        assertThat(repository.getNode(pathFactory.create("/b")), is(sameInstance(node_b)));
+
+        // Removing a node with the same name will reduce the index ...
+        repository.removeNode(context, node_a2);
+        assertThat(repository.getRoot().getChildren().size(), is(3));
+        assertThat(repository.getRoot().getChildren(), hasItems(node_a1, node_b, node_a3));
+        assertThat(node_a1.getName().getIndex(), is(1));
+        assertThat(node_b.getName().hasIndex(), is(false));
+        assertThat(node_a3.getName().getIndex(), is(2));
+
+        // Removing a node with the same name will reduce the index ...
+        repository.removeNode(context, node_a1);
+        assertThat(repository.getRoot().getChildren().size(), is(2));
+        assertThat(repository.getRoot().getChildren(), hasItems(node_b, node_a3));
+        assertThat(node_b.getName().hasIndex(), is(false));
+        assertThat(node_a3.getName().hasIndex(), is(false));
+        assertThat(repository.getNodesByUuid().size(), is(3));
+    }
+
+    @Test
+    public void shouldMoveNodes() {
+        InMemoryNode root = repository.getRoot();
+        InMemoryNode node_a = repository.createNode(context, root, nameFactory.create("a"), null);
+        InMemoryNode node_b = repository.createNode(context, node_a, nameFactory.create("b"), null);
+        InMemoryNode node_c = repository.createNode(context, node_b, nameFactory.create("c"), null);
+        InMemoryNode node_d = repository.createNode(context, root, nameFactory.create("d"), null);
+        InMemoryNode node_e = repository.createNode(context, node_d, nameFactory.create("e"), null);
+        InMemoryNode node_b2 = repository.createNode(context, node_d, nameFactory.create("b"), null);
+
+        assertThat(repository.getNodesByUuid().size(), is(7));
+        assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+        assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+        assertThat(repository.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
+        assertThat(repository.getNode(pathFactory.create("/a/b/c")), is(sameInstance(node_c)));
+        assertThat(repository.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
+        assertThat(repository.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
+        assertThat(repository.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
+
+        repository.moveNode(context, node_b, node_d);
+
+        assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+        assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+        assertThat(repository.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
+        assertThat(repository.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
+        assertThat(repository.getNode(pathFactory.create("/d/b[1]")), is(sameInstance(node_b2)));
+        assertThat(repository.getNode(pathFactory.create("/d/b[2]")), is(sameInstance(node_b)));
+        assertThat(repository.getNode(pathFactory.create("/d/b[2]/c")), is(sameInstance(node_c)));
+
+        repository.moveNode(context, node_b, node_e);
+
+        assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+        assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+        assertThat(repository.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
+        assertThat(repository.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
+        assertThat(repository.getNode(pathFactory.create("/d/e/b")), is(sameInstance(node_b)));
+        assertThat(repository.getNode(pathFactory.create("/d/e/b/c")), is(sameInstance(node_c)));
+        assertThat(repository.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
+    }
+
+    @Test
+    public void shouldCopyNodes() {
+        InMemoryNode root = repository.getRoot();
+        InMemoryNode node_a = repository.createNode(context, root, nameFactory.create("a"), null);
+        InMemoryNode node_b = repository.createNode(context, node_a, nameFactory.create("b"), null);
+        InMemoryNode node_c = repository.createNode(context, node_b, nameFactory.create("c"), null);
+        InMemoryNode node_d = repository.createNode(context, root, nameFactory.create("d"), null);
+        InMemoryNode node_e = repository.createNode(context, node_d, nameFactory.create("e"), null);
+        InMemoryNode node_b2 = repository.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);
+
+        assertThat(repository.getNodesByUuid().size(), is(7));
+        assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+        assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+        assertThat(repository.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
+        assertThat(repository.getNode(pathFactory.create("/a/b/c")), is(sameInstance(node_c)));
+        assertThat(repository.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
+        assertThat(repository.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
+        assertThat(repository.getNode(pathFactory.create("/d/b")), is(sameInstance(node_b2)));
+
+        assertThat(repository.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+
+        repository.copyNode(context, node_b, node_d, true, new HashMap<UUID, UUID>());
+
+        assertThat(repository.getNodesByUuid().size(), is(9));
+        assertThat(repository.getNode(pathFactory.create("/")), is(sameInstance(repository.getRoot())));
+        assertThat(repository.getNode(pathFactory.create("/a")), is(sameInstance(node_a)));
+        assertThat(repository.getNode(pathFactory.create("/a/b")), is(sameInstance(node_b)));
+        assertThat(repository.getNode(pathFactory.create("/a/b/c")), is(sameInstance(node_c)));
+        assertThat(repository.getNode(pathFactory.create("/d")), is(sameInstance(node_d)));
+        assertThat(repository.getNode(pathFactory.create("/d/e")), is(sameInstance(node_e)));
+        assertThat(repository.getNode(pathFactory.create("/d/b[1]")), is(sameInstance(node_b2)));
+        assertThat(repository.getNode(pathFactory.create("/d/b[2]")), is(notNullValue()));
+        assertThat(repository.getNode(pathFactory.create("/d/b[2]/c")), is(notNullValue()));
+
+        assertThat(repository.getNode(pathFactory.create("/a/b")).getProperties().get(propertyName), is(property));
+        assertThat(repository.getNode(pathFactory.create("/d/b[2]")).getProperties().get(propertyName), is(property));
+    }
+
+    @Test
+    public void shouldCreateRepositoryStructure() {
+        repository.createNode(context, "/a").setProperty(context, "name", "value").setProperty(context,
+                                                                                               "desc",
+                                                                                               "Some description");
+        repository.createNode(context, "/a/b").setProperty(context, "name", "value2").setProperty(context,
+                                                                                                  "desc",
+                                                                                                  "Some description 2");
+        assertThat(repository.getNode(context, "/a").getProperty(context, "name").getValuesAsArray(), is(new Object[] {"value"}));
+        assertThat(repository.getNode(context, "/a").getProperty(context, "desc").getValuesAsArray(),
+                   is(new Object[] {"Some description"}));
+        assertThat(repository.getNode(context, "/a/b").getProperty(context, "name").getValuesAsArray(),
+                   is(new Object[] {"value2"}));
+        assertThat(repository.getNode(context, "/a/b").getProperty(context, "desc").getValuesAsArray(),
+                   is(new Object[] {"Some description 2"}));
+    }
+}

Modified: trunk/docs/examples/gettingstarted/pom.xml
===================================================================
--- trunk/docs/examples/gettingstarted/pom.xml	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/docs/examples/gettingstarted/pom.xml	2009-01-16 02:37:49 UTC (rev 710)
@@ -52,11 +52,6 @@
       </dependency>
       <dependency>
         <groupId>org.jboss.dna</groupId>
-        <artifactId>dna-connector-inmemory</artifactId>
-        <version>${pom.version}</version>
-      </dependency>
-      <dependency>
-        <groupId>org.jboss.dna</groupId>
         <artifactId>dna-connector-jbosscache</artifactId>
         <version>${pom.version}</version>
       </dependency>

Modified: trunk/docs/examples/gettingstarted/repositories/pom.xml
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/pom.xml	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/docs/examples/gettingstarted/repositories/pom.xml	2009-01-16 02:37:49 UTC (rev 710)
@@ -36,12 +36,6 @@
     </dependency>
     <dependency>
       <groupId>org.jboss.dna</groupId>
-      <artifactId>dna-connector-inmemory</artifactId>
-      <version>${pom.version}</version>
-      <scope>compile</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.jboss.dna</groupId>
       <artifactId>dna-connector-jbosscache</artifactId>
       <version>${pom.version}</version>
       <scope>runtime</scope>

Modified: trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/java/org/jboss/example/dna/repository/RepositoryClient.java	2009-01-16 02:37:49 UTC (rev 710)
@@ -43,11 +43,11 @@
 import net.jcip.annotations.Immutable;
 import org.jboss.dna.common.text.NoOpEncoder;
 import org.jboss.dna.common.util.CheckArg;
-import org.jboss.dna.connector.inmemory.InMemoryRepositorySource;
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.ExecutionContextFactory;
 import org.jboss.dna.graph.Graph;
 import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource;
 import org.jboss.dna.graph.property.Path;
 import org.jboss.dna.graph.property.PathFactory;
 import org.jboss.dna.graph.property.PathNotFoundException;

Modified: trunk/docs/examples/gettingstarted/repositories/src/main/resources/configRepository.xml
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/main/resources/configRepository.xml	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/docs/examples/gettingstarted/repositories/src/main/resources/configRepository.xml	2009-01-16 02:37:49 UTC (rev 710)
@@ -27,15 +27,15 @@
 <dna:system xmlns:dna="http://www.jboss.org/dna" xmlns:jcr="http://www.jcp.org/jcr/1.0">
     <!-- Define the sources from which content is made available -->
     <dna:sources>
-        <dna:source jcr:name="SourceA" dna:name="Cars" dna:classname="org.jboss.dna.connector.inmemory.InMemoryRepositorySource" dna:retryLimit="3" />
-        <dna:source jcr:name="SourceB" dna:name="Aircraft" dna:classname="org.jboss.dna.connector.inmemory.InMemoryRepositorySource" />
+        <dna:source jcr:name="SourceA" dna:name="Cars" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" dna:retryLimit="3" />
+        <dna:source jcr:name="SourceB" dna:name="Aircraft" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" />
         <dna:source jcr:name="SourceC" dna:name="Vehicles" dna:classname="org.jboss.dna.connector.federation.FederatedRepositorySource" 
                     dna:repositoryName="Configuration Repository"
                     dna:configurationSourceName="Configuration" 
                     dna:configurationSourcePath="/dna:system/dna:federatedRepositories/Vehicles" 
                     dna:repositoryConnectionFactoryJndiName="/dna/connectionFactory"
                     dna:executionContextFactoryJndiName="/dna/contextFactory"/>
-        <dna:source jcr:name="SourceD" dna:name="Cache" dna:classname="org.jboss.dna.connector.inmemory.InMemoryRepositorySource" />
+        <dna:source jcr:name="SourceD" dna:name="Cache" dna:classname="org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource" />
     </dna:sources>
     <dna:federatedRepositories>
         <!-- This section defines from where the content of the 'Vehicles' federated repository is obtained.

Modified: trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/docs/examples/gettingstarted/repositories/src/test/java/org/jboss/example/dna/repository/RepositoryClientTest.java	2009-01-16 02:37:49 UTC (rev 710)
@@ -125,7 +125,7 @@
         assertThat(children.size(), is(0));
         assertThat(properties.containsKey("jcr:primaryType"), is(true));
         assertThat(properties.containsKey("dna:uuid"), is(true));
-        assertProperty("dna:classname", "org.jboss.dna.connector.inmemory.InMemoryRepositorySource");
+        assertProperty("dna:classname", org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource.class.getName());
         assertProperty("dna:name", "Cars");
         assertProperty("dna:retryLimit", "3");
         assertThat(properties.size(), is(5));

Modified: trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml
===================================================================
--- trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/docs/gettingstarted/src/main/docbook/en-US/content/understanding_dna.xml	2009-01-16 02:37:49 UTC (rev 710)
@@ -360,12 +360,6 @@
       <itemizedlist>
         <listitem>
           <para>
-            <emphasis role="strong">In-Memory Connector</emphasis>
-            - Creates a transient, in-memory repository.
-          </para>
-        </listitem>
-        <listitem>
-          <para>
             <emphasis role="strong">JBoss Cache Connector</emphasis>
             - Uses a JBoss Cache instance as a repository.  JBoss Cache is a powerful cache capable of persisting the information
  						and being clustered for concurrent use by multiple processes.

Modified: trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/docs/reference/src/main/docbook/en-US/content/introduction.xml	2009-01-16 02:37:49 UTC (rev 710)
@@ -331,13 +331,6 @@
         </listitem>
         <listitem>
           <para>
-            <emphasis role="strong">dna-connector-inmemory</emphasis>
-            is a simple DNA repository connector that manages content within memory. This can be used as a simple cache or as a
-            transient repository.
-          </para>
-        </listitem>
-        <listitem>
-          <para>
             <emphasis role="strong">dna-connector-jbosscache</emphasis>
             is a DNA repository connector that manages content within a
             <ulink url="http://www.jboss.org/jbosscache/">JBoss Cache</ulink>

Modified: trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/docs/reference/src/main/docbook/en-US/content/repositories.xml	2009-01-16 02:37:49 UTC (rev 710)
@@ -587,9 +587,9 @@
 	        and would like to help create it, please <link linkend="preface">join the community</link>.
 				</para>
 		    <para>In lieu of a Maven archetype, you may find it easier to start with a small existing connector project.
-					The <emphasis role="strong">dna-connector-inmemory</emphasis> project is small, but it may be tough to separate
+					The <emphasis role="strong">dna-connector-filesystem</emphasis> project is small, but it may be tough to separate
 					the stuff that every connector needs from the extra code and data structures that manage the content.
-		    	See the subversion repository: <ulink url="&Subversion;trunk/extensions/dna-connector-inmemory/">&Subversion;trunk/extensions/dna-connector-inmemory/</ulink>
+		    	See the subversion repository: <ulink url="&Subversion;trunk/extensions/dna-connector-filesystem/">&Subversion;trunk/extensions/dna-connector-filesystem/</ulink>
 		    </para>
 		  </note>
 	    <para>

Modified: trunk/docs/reference/src/main/docbook/en-US/custom.dtd
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/custom.dtd	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/docs/reference/src/main/docbook/en-US/custom.dtd	2009-01-16 02:37:49 UTC (rev 710)
@@ -75,6 +75,8 @@
 <!ENTITY RepositoryConnectionFactory	"<ulink url='&API;graph/connector/RepositoryConnectionFactory.html'><interface>RepositoryConnectionFactory</interface></ulink>">
 <!ENTITY RepositorySourceListener			"<ulink url='&API;graph/connector/RepositorySourceListener.html'><interface>RepositorySourceListener</interface></ulink>">
 <!ENTITY RepositorySourceCapabilities	"<ulink url='&API;graph/connector/RepositorySourceCapabilities.html'><classname>RepositorySourceCapabilities</classname></ulink>">
+<!ENTITY InMemoryRepository			  		"<ulink url='&API;graph.connector/inmemory/InMemoryRepository.html'><classname>InMemoryRepository</classname></ulink>">
+<!ENTITY InMemoryRepositorySource  		"<ulink url='&API;graph.connector/inmemory/InMemoryRepositorySource.html'><classname>InMemoryRepositorySource</classname></ulink>">
 <!ENTITY CachePolicy							    "<ulink url='&API;graph/cache/CachePolicy.html'><interface>CachePolicy</interface></ulink>">
 <!ENTITY Request					       			"<ulink url='&API;graph/request/Requests.html'><classname>Request</classname></ulink>">
 <!ENTITY CompositeRequest					    "<ulink url='&API;graph/request/CompositeRequest.html'><classname>CompositeRequest</classname></ulink>">
@@ -110,8 +112,6 @@
 
 <!-- Types in extensions/ -->
 
-<!ENTITY InMemoryRepository			  		"<ulink url='&API;connector/inmemory/InMemoryRepository.html'><classname>InMemoryRepository</classname></ulink>">
-<!ENTITY InMemoryRepositorySource  		"<ulink url='&API;connector/inmemory/InMemoryRepositorySource.html'><classname>InMemoryRepositorySource</classname></ulink>">
 <!ENTITY JBossCacheRepository			  	"<ulink url='&API;connector/jbosscache/JBossCacheRepository.html'><classname>JBossCacheRepository</classname></ulink>">
 <!ENTITY JBossCacheSource  						"<ulink url='&API;connector/jbosscache/JBossCacheSource.html'><classname>JBossCacheSource</classname></ulink>">
 <!ENTITY FederatedRepositorySource  	"<ulink url='&API;connector/federation/FederatedRepositorySource.html'><classname>FederatedRepositorySource</classname></ulink>">

Modified: trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties
===================================================================
--- trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/extensions/dna-connector-federation/src/test/resources/log4j.properties	2009-01-16 02:37:49 UTC (rev 710)
@@ -9,7 +9,7 @@
 
 # Set up the default logging to be INFO level, then override specific units
 log4j.logger.org.jboss.dna=INFO
-log4j.logger.org.jboss.dna.connector.federation.executor=TRACE
+log4j.logger.org.jboss.dna.connector.federation.executor=INFO
 
 # Jackrabbit logging
 log4j.logger.org.apache.jackrabbit=WARN, stdout

Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml	2009-01-15 21:15:57 UTC (rev 709)
+++ trunk/pom.xml	2009-01-16 02:37:49 UTC (rev 710)
@@ -126,7 +126,6 @@
 		<module>extensions/dna-sequencer-xml</module>
 		<module>extensions/dna-sequencer-zip</module>
 		<module>extensions/dna-connector-federation</module>
-		<module>extensions/dna-connector-inmemory</module>
 		<module>extensions/dna-connector-jbosscache</module>
 		<module>extensions/dna-connector-svn</module>
 		<module>extensions/dna-connector-store-jpa</module>
@@ -401,11 +400,6 @@
 			</dependency>
 			<dependency>
 				<groupId>org.jboss.dna</groupId>
-				<artifactId>dna-connector-inmemory</artifactId>
-				<version>${pom.version}</version>
-			</dependency>
-			<dependency>
-				<groupId>org.jboss.dna</groupId>
 				<artifactId>dna-mimetype-detector-aperture</artifactId>
 				<version>${pom.version}</version>
 			</dependency>




More information about the dna-commits mailing list