[dna-commits] DNA SVN: r780 - in trunk/dna-jcr/src: main/java/org/jboss/dna/jcr/cache and 2 other directories.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Tue Mar 17 15:16:04 EDT 2009


Author: rhauch
Date: 2009-03-17 15:16:04 -0400 (Tue, 17 Mar 2009)
New Revision: 780

Added:
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/AbstractChildrenTest.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedChildrenTest.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ImmutableChildrenTest.java
Modified:
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/Children.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/EmptyChildren.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java
   trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NodeInfo.java
   trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
Log:
DNA-194 Implement update JCR capability

Added mutable versions of the classes used to store node, property and children representations.

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java	2009-03-17 15:45:11 UTC (rev 779)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java	2009-03-17 19:16:04 UTC (rev 780)
@@ -62,6 +62,7 @@
 import org.jboss.dna.graph.property.ValueFormatException;
 import org.jboss.dna.jcr.cache.ChildNode;
 import org.jboss.dna.jcr.cache.Children;
+import org.jboss.dna.jcr.cache.EmptyChildren;
 import org.jboss.dna.jcr.cache.ImmutableChildren;
 import org.jboss.dna.jcr.cache.ImmutableNodeInfo;
 import org.jboss.dna.jcr.cache.NodeInfo;
@@ -131,7 +132,7 @@
     private final ReferenceMap<UUID, AbstractJcrNode> jcrNodes;
     private final ReferenceMap<PropertyId, AbstractJcrProperty> jcrProperties;
 
-    private final HashMap<UUID, NodeInfo> cachedNodes;
+    private final HashMap<UUID, ImmutableNodeInfo> cachedNodes;
     private final HashMap<UUID, NodeInfo> changedNodes;
 
     public SessionCache( JcrSession session,
@@ -159,7 +160,7 @@
         this.jcrNodes = new ReferenceMap<UUID, AbstractJcrNode>(ReferenceType.STRONG, ReferenceType.SOFT);
         this.jcrProperties = new ReferenceMap<PropertyId, AbstractJcrProperty>(ReferenceType.STRONG, ReferenceType.SOFT);
 
-        this.cachedNodes = new HashMap<UUID, NodeInfo>();
+        this.cachedNodes = new HashMap<UUID, ImmutableNodeInfo>();
         this.changedNodes = new HashMap<UUID, NodeInfo>();
     }
 
@@ -554,9 +555,10 @@
                             // Now process all of the nodes that we loaded, again starting at the top and going down ...
                             for (Path batchPath : pathsInBatch) {
                                 org.jboss.dna.graph.Node dnaNode = batchResults.getNode(batchPath);
-                                childInfo = createNodeInfoFrom(dnaNode, info);
-                                this.cachedNodes.put(childInfo.getUuid(), childInfo);
-                                info = childInfo;
+                                ImmutableNodeInfo originalChildInfo = createNodeInfoFrom(dnaNode, info);
+                                this.cachedNodes.put(originalChildInfo.getUuid(), originalChildInfo);
+                                childInfo = originalChildInfo;
+                                info = originalChildInfo;
                             }
                         } else {
                             // This is the last path, so do it a little more efficiently than above ...
@@ -651,12 +653,12 @@
      * @throws ItemNotFoundException if the node does not exist in the repository
      * @throws RepositoryException if there was an error obtaining this information from the repository
      */
-    protected NodeInfo loadFromGraph( UUID uuid,
-                                      NodeInfo parentInfo ) throws ItemNotFoundException, RepositoryException {
+    protected ImmutableNodeInfo loadFromGraph( UUID uuid,
+                                               NodeInfo parentInfo ) throws ItemNotFoundException, RepositoryException {
         // Load the node information from the store ...
         try {
             org.jboss.dna.graph.Node node = store.getNodeAt(uuid);
-            NodeInfo info = createNodeInfoFrom(node, parentInfo);
+            ImmutableNodeInfo info = createNodeInfoFrom(node, parentInfo);
             this.cachedNodes.put(info.getUuid(), info);
             return info;
         } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
@@ -681,12 +683,12 @@
      * @throws PathNotFoundException if the node does not exist in the repository
      * @throws RepositoryException if there was an error obtaining this information from the repository
      */
-    protected NodeInfo loadFromGraph( Path path,
-                                      NodeInfo parentInfo ) throws PathNotFoundException, RepositoryException {
+    protected ImmutableNodeInfo loadFromGraph( Path path,
+                                               NodeInfo parentInfo ) throws PathNotFoundException, RepositoryException {
         // Load the node information from the store ...
         try {
             org.jboss.dna.graph.Node node = store.getNodeAt(path);
-            NodeInfo info = createNodeInfoFrom(node, parentInfo);
+            ImmutableNodeInfo info = createNodeInfoFrom(node, parentInfo);
             this.cachedNodes.put(info.getUuid(), info);
             return info;
         } catch (org.jboss.dna.graph.property.PathNotFoundException e) {
@@ -706,8 +708,8 @@
      * @throws RepositoryException if there is an error determining the child {@link NodeDefinition} for the supplied node,
      *         preventing the node information from being constructed
      */
-    private NodeInfo createNodeInfoFrom( org.jboss.dna.graph.Node graphNode,
-                                         NodeInfo parentInfo ) throws RepositoryException {
+    private ImmutableNodeInfo createNodeInfoFrom( org.jboss.dna.graph.Node graphNode,
+                                                  NodeInfo parentInfo ) throws RepositoryException {
         // Now get the DNA node's UUID and find the DNA property containing the UUID ...
         Location location = graphNode.getLocation();
         ValueFactories factories = context.getValueFactories();
@@ -953,7 +955,8 @@
 
         // Create the node information ...
         UUID parentUuid = parentInfo != null ? parentInfo.getUuid() : null;
-        Children children = new ImmutableChildren(parentUuid, graphNode.getChildren());
+        List<Location> locations = graphNode.getChildren();
+        Children children = locations.isEmpty() ? new EmptyChildren(parentUuid) : new ImmutableChildren(parentUuid, locations);
         props = Collections.unmodifiableMap(props);
         return new ImmutableNodeInfo(location, primaryTypeName, definition.getId(), parentUuid, children, props);
     }

Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java	                        (rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java	2009-03-17 19:16:04 UTC (rev 780)
@@ -0,0 +1,101 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA is licensed
+ * to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.jcr.cache;
+
+import java.util.List;
+import java.util.ListIterator;
+import java.util.UUID;
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.PathFactory;
+
+/**
+ * A {@link NotThreadSafe non-thread safe} implementation of {@link Children} that can be modified in place. This is typically
+ * used to capture changes made within a session.
+ */
+ at NotThreadSafe
+public class ChangedChildren extends ImmutableChildren {
+
+    public ChangedChildren( Children original ) {
+        super(original);
+    }
+
+    /**
+     * Creates an empty instance.
+     * 
+     * @param parentUuid the UUID of the parent node
+     */
+    protected ChangedChildren( UUID parentUuid ) {
+        super(parentUuid);
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.jcr.cache.ImmutableChildren#with(org.jboss.dna.graph.property.Name, java.util.UUID,
+     *      org.jboss.dna.graph.property.PathFactory)
+     */
+    @Override
+    public ChangedChildren with( Name newChildName,
+                                 UUID newChildUuid,
+                                 PathFactory pathFactory ) {
+        // Simply add the node to this object ...
+        super.add(newChildName, newChildUuid, pathFactory);
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see org.jboss.dna.jcr.cache.ImmutableChildren#without(org.jboss.dna.jcr.cache.ChildNode,
+     *      org.jboss.dna.graph.property.PathFactory)
+     */
+    @Override
+    public ChangedChildren without( ChildNode child,
+                                    PathFactory pathFactory ) {
+        // Make sure this object contains the child ...
+        if (!childrenByUuid.containsKey(child.getUuid())) {
+            return this;
+        }
+        // Remove the child fro this object, then adjust the remaining child node instances that follow it ...
+        Name childName = child.getName();
+        List<ChildNode> childrenWithSameName = childrenByName.get(childName);
+        int snsIndex = child.getSnsIndex();
+        if (snsIndex > childrenWithSameName.size()) {
+            // The child node (with that SNS index) is no longer here) ...
+            return this;
+        }
+        ListIterator<ChildNode> iter = childrenWithSameName.listIterator(--snsIndex);
+        assert iter.hasNext();
+        iter.next(); // start ...
+        iter.remove(); // removes the item that was last returned from 'next()'
+        while (iter.hasNext()) {
+            ChildNode next = iter.next();
+            ChildNode newNext = next.with(pathFactory.createSegment(childName, ++snsIndex));
+            iter.set(newNext);
+        }
+        return this;
+    }
+
+}


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

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/Children.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/Children.java	2009-03-17 15:45:11 UTC (rev 779)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/Children.java	2009-03-17 19:16:04 UTC (rev 780)
@@ -27,7 +27,6 @@
 import java.util.UUID;
 import org.jboss.dna.graph.property.Name;
 import org.jboss.dna.graph.property.Path;
-import org.jboss.dna.graph.property.PathFactory;
 
 /**
  * Class that maintains the ordered list of {@link ChildNode} instances yet allows fast access to the children with a specified
@@ -74,15 +73,4 @@
      */
     Iterator<ChildNode> getChildren( Name name );
 
-    /**
-     * Create another Children object that is equivalent to this node but with the supplied child added.
-     * 
-     * @param newChildName the name of the new child; may not be null
-     * @param newChildUuid the UUID of the new child; may not be null
-     * @param pathFactory the factory that can be used to create Path and/or Path.Segment instances.
-     * @return the new Children object; never null
-     */
-    Children with( Name newChildName,
-                   UUID newChildUuid,
-                   PathFactory pathFactory );
 }

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/EmptyChildren.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/EmptyChildren.java	2009-03-17 15:45:11 UTC (rev 779)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/EmptyChildren.java	2009-03-17 19:16:04 UTC (rev 780)
@@ -37,7 +37,7 @@
 @Immutable
 public final class EmptyChildren implements Children {
 
-    private static final Iterator<ChildNode> EMPTY_ITERATOR = new EmptyIterator<ChildNode>();
+    static final Iterator<ChildNode> EMPTY_ITERATOR = new EmptyIterator<ChildNode>();
 
     private final UUID parentUuid;
 
@@ -99,13 +99,36 @@
         return EMPTY_ITERATOR;
     }
 
-    public ImmutableChildren with( Name newChildName,
-                                   UUID newChildUuid,
-                                   PathFactory pathFactory ) {
-        return new ImmutableChildren(this, newChildName, newChildUuid, pathFactory);
+    /**
+     * Create another Children object that is equivalent to this node but with the supplied child added.
+     * 
+     * @param newChildName the name of the new child; may not be null
+     * @param newChildUuid the UUID of the new child; may not be null
+     * @param pathFactory the factory that can be used to create Path and/or Path.Segment instances.
+     * @return the new Children object; never null
+     */
+    public ChangedChildren with( Name newChildName,
+                                 UUID newChildUuid,
+                                 PathFactory pathFactory ) {
+        ChangedChildren result = new ChangedChildren(this);
+        result.add(newChildName, newChildUuid, pathFactory);
+        return result;
     }
 
     /**
+     * Create another Children object that is equivalent to this node but without the supplied child. If the supplied child is not
+     * a current child, this method silently returns this same instance (since it has not changed).
+     * 
+     * @param child the child to be removed; may not be null
+     * @param pathFactory the factory that can be used to create Path and/or Path.Segment instances.
+     * @return the new Children object; never null
+     */
+    public ChangedChildren without( ChildNode child,
+                                    PathFactory pathFactory ) {
+        return new ChangedChildren(this.parentUuid);
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#toString()

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java	2009-03-17 15:45:11 UTC (rev 779)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java	2009-03-17 19:16:04 UTC (rev 780)
@@ -42,16 +42,14 @@
  * An immutable implementation of {@link Children}.
  */
 @Immutable
-public final class ImmutableChildren implements Children {
-    private final UUID parentUuid;
-    private final Map<UUID, ChildNode> childrenByUuid;
-    private final ListMultimap<Name, ChildNode> childrenByName;
+public class ImmutableChildren implements Children {
+    protected final UUID parentUuid;
+    protected final Map<UUID, ChildNode> childrenByUuid;
+    protected final ListMultimap<Name, ChildNode> childrenByName;
 
     public ImmutableChildren( UUID parentUuid,
                               Iterable<Location> children ) {
-        this.parentUuid = parentUuid;
-        this.childrenByUuid = new HashMap<UUID, ChildNode>();
-        this.childrenByName = new LinkedListMultimap<Name, ChildNode>();
+        this(parentUuid);
         for (Location childLocation : children) {
             UUID childUuid = childLocation.getUuid();
             Path.Segment segment = childLocation.getPath().getLastSegment();
@@ -62,10 +60,13 @@
         }
     }
 
-    protected ImmutableChildren( Children original,
-                                 Name additionalChildName,
-                                 UUID childUuid,
-                                 PathFactory pathFactory ) {
+    public ImmutableChildren( UUID parentUuid ) {
+        this.parentUuid = parentUuid;
+        this.childrenByUuid = new HashMap<UUID, ChildNode>();
+        this.childrenByName = new LinkedListMultimap<Name, ChildNode>();
+    }
+
+    protected ImmutableChildren( Children original ) {
         this.parentUuid = original.getParentUuid();
         this.childrenByUuid = new HashMap<UUID, ChildNode>();
         this.childrenByName = new LinkedListMultimap<Name, ChildNode>();
@@ -75,11 +76,38 @@
             this.childrenByName.put(child.getName(), child);
             this.childrenByUuid.put(child.getUuid(), child);
         }
+    }
+
+    protected ImmutableChildren( Children original,
+                                 Name additionalChildName,
+                                 UUID childUuid,
+                                 PathFactory pathFactory ) {
+        this(original);
+        add(additionalChildName, childUuid, pathFactory);
+    }
+
+    /**
+     * Utility method that adds a child with the supplied name. This method is not exposed publicly, ensuring that this class
+     * remains publicly immutable. Subclasses that use this method (in places other than constructors) will no longer be
+     * {@link Immutable immutable}.
+     * 
+     * @param additionalChildName
+     * @param childUuid
+     * @param pathFactory
+     * @return the child node that was just added; never null
+     */
+    protected ChildNode add( Name additionalChildName,
+                             UUID childUuid,
+                             PathFactory pathFactory ) {
+        ChildNode existing = this.childrenByUuid.get(childUuid);
+        if (existing != null) return existing;
+
         List<ChildNode> childrenWithName = this.childrenByName.get(additionalChildName);
         Path.Segment segment = pathFactory.createSegment(additionalChildName, childrenWithName.size() + 1);
         ChildNode additionalChild = new ChildNode(childUuid, segment);
         this.childrenByName.put(additionalChildName, additionalChild);
         this.childrenByUuid.put(childUuid, additionalChild);
+        return additionalChild;
     }
 
     /**
@@ -139,13 +167,39 @@
         return new ReadOnlyIterator<ChildNode>(this.childrenByName.get(name).iterator());
     }
 
-    public ImmutableChildren with( Name newChildName,
-                                   UUID newChildUuid,
-                                   PathFactory pathFactory ) {
-        return new ImmutableChildren(this, newChildName, newChildUuid, pathFactory);
+    /**
+     * Create another Children object that is equivalent to this node but with the supplied child added.
+     * 
+     * @param newChildName the name of the new child; may not be null
+     * @param newChildUuid the UUID of the new child; may not be null
+     * @param pathFactory the factory that can be used to create Path and/or Path.Segment instances.
+     * @return the new Children object; never null
+     */
+    public ChangedChildren with( Name newChildName,
+                                 UUID newChildUuid,
+                                 PathFactory pathFactory ) {
+        // Create a mutable version ...
+        ChangedChildren newChildren = new ChangedChildren(this);
+        return newChildren.with(newChildName, newChildUuid, pathFactory);
     }
 
     /**
+     * Create another Children object that is equivalent to this node but without the supplied child.
+     * 
+     * @param child the child to be removed; may not be null
+     * @param pathFactory the factory that can be used to create Path and/or Path.Segment instances.
+     * @return the new Children object; never null
+     */
+    public ChangedChildren without( ChildNode child,
+                                    PathFactory pathFactory ) {
+        if (this.childrenByUuid.containsKey(child.getUuid()) && this.size() == 1) {
+            return new ChangedChildren(this.parentUuid);
+        }
+        ChangedChildren newChildren = new ChangedChildren(this);
+        return newChildren.without(child, pathFactory);
+    }
+
+    /**
      * {@inheritDoc}
      * 
      * @see java.lang.Object#toString()

Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NodeInfo.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NodeInfo.java	2009-03-17 15:45:11 UTC (rev 779)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NodeInfo.java	2009-03-17 19:16:04 UTC (rev 780)
@@ -62,7 +62,7 @@
     /**
      * Get the children for this node.
      * 
-     * @return the children; never null but possibly empty
+     * @return the immutable children; never null but possibly empty
      */
     public Children getChildren();
 

Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java	2009-03-17 15:45:11 UTC (rev 779)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java	2009-03-17 19:16:04 UTC (rev 780)
@@ -52,6 +52,7 @@
 import org.jboss.dna.graph.ExecutionContext;
 import org.jboss.dna.graph.property.Name;
 import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.jcr.cache.ChangedChildren;
 import org.jboss.dna.jcr.cache.Children;
 import org.jboss.dna.jcr.cache.EmptyChildren;
 import org.jboss.dna.jcr.cache.NodeInfo;
@@ -151,7 +152,11 @@
 
     protected void addChild( Name childName,
                              UUID childUuid ) {
-        children = children.with(childName, childUuid, context.getValueFactories().getPathFactory());
+        if (children instanceof EmptyChildren) {
+            children = ((EmptyChildren)children).with(childName, childUuid, context.getValueFactories().getPathFactory());
+        } else if (children instanceof ChangedChildren) {
+            children = ((ChangedChildren)children).with(childName, childUuid, context.getValueFactories().getPathFactory());
+        }
         stub(info.getChildren()).toReturn(children);
     }
 

Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/AbstractChildrenTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/AbstractChildrenTest.java	                        (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/AbstractChildrenTest.java	2009-03-17 19:16:04 UTC (rev 780)
@@ -0,0 +1,168 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA is licensed
+ * to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.jcr.cache;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+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.Path.Segment;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @param <ChildrenType> the type for the {@link #children} variable
+ */
+public abstract class AbstractChildrenTest<ChildrenType extends Children> {
+
+    protected ChildrenType children;
+    protected ExecutionContext context;
+    protected PathFactory pathFactory;
+    protected NameFactory nameFactory;
+    protected UUID parentUuid;
+    protected UUID firstChildUuid;
+    protected Name firstChildName;
+    protected ChildNode firstChild;
+
+    @Before
+    public void beforeEach() {
+        context = new ExecutionContext();
+        pathFactory = context.getValueFactories().getPathFactory();
+        nameFactory = context.getValueFactories().getNameFactory();
+
+        parentUuid = UUID.randomUUID();
+        firstChildUuid = UUID.randomUUID();
+        firstChildName = nameFactory.create("childA");
+    }
+
+    protected Name name( String name ) {
+        return nameFactory.create(name);
+    }
+
+    protected void assertChildNodesWithName( Children children,
+                                             String childName,
+                                             Object... childNodes ) {
+        Name name = name(childName);
+        Iterator<ChildNode> iter = children.getChildren(name);
+        int expectedSnsIndex = 1;
+        for (Object expectedChild : childNodes) {
+            assertThat(iter.hasNext(), is(true));
+            ChildNode next = iter.next();
+            assertThat(next.getName(), is(name));
+            assertThat(next.getSnsIndex(), is(expectedSnsIndex++));
+            if (expectedChild instanceof ChildNode) {
+                assertThat(next, is(sameInstance(expectedChild)));
+            } else if (expectedChild instanceof Name) {
+                Name expectedName = (Name)expectedChild;
+                assertThat(next.getName(), is(expectedName));
+            } else if (expectedChild instanceof String) {
+                Name expectedName = name((String)expectedChild);
+                assertThat(next.getName(), is(expectedName));
+            }
+        }
+        assertThat(iter.hasNext(), is(false));
+    }
+
+    protected void assertChildNodes( Children children,
+                                     Object... childNodes ) {
+        Iterator<ChildNode> iter = children.iterator();
+        Map<Name, AtomicInteger> expectedSnsIndexes = new HashMap<Name, AtomicInteger>();
+        for (Object expectedChild : childNodes) {
+            assertThat(iter.hasNext(), is(true));
+            ChildNode next = iter.next();
+            Name actualName = next.getName();
+            // Check the name ...
+            if (expectedChild instanceof ChildNode) {
+                assertThat(next, is(sameInstance(expectedChild)));
+            } else if (expectedChild instanceof Name) {
+                Name expectedName = (Name)expectedChild;
+                assertThat(actualName, is(expectedName));
+            } else if (expectedChild instanceof String) {
+                Name expectedName = name((String)expectedChild);
+                assertThat(actualName, is(expectedName));
+            }
+            // Check the SNS ...
+            AtomicInteger expectedSns = expectedSnsIndexes.get(actualName);
+            if (expectedSns == null) {
+                expectedSns = new AtomicInteger(1);
+                expectedSnsIndexes.put(actualName, expectedSns);
+            }
+            assertThat(next.getSnsIndex(), is(expectedSns.getAndIncrement()));
+        }
+        assertThat(iter.hasNext(), is(false));
+    }
+
+    protected void assertSameContent( Children children,
+                                      Children other ) {
+        Iterator<ChildNode> iter = children.iterator();
+        Iterator<ChildNode> otherIter = other.iterator();
+        while (iter.hasNext()) {
+            assertThat(otherIter.hasNext(), is(true));
+            ChildNode next = iter.next();
+            ChildNode otherNext = otherIter.next();
+            assertThat(next, is(otherNext));
+        }
+        assertThat(iter.hasNext(), is(false));
+        assertThat(otherIter.hasNext(), is(false));
+    }
+
+    @Test
+    public void shouldFindFirstChildByUuid() {
+        ChildNode firstChild = children.getChild(firstChildUuid);
+        assertThat(firstChild, is(notNullValue()));
+        assertThat(firstChild, is(sameInstance(this.firstChild)));
+        assertThat(firstChild.getUuid(), is(firstChildUuid));
+        assertThat(firstChild.getName(), is(firstChildName));
+        assertThat(firstChild.getSnsIndex(), is(1));
+        assertThat(firstChild.getSegment().getIndex(), is(1));
+        assertThat(firstChild.getSegment().getName(), is(firstChildName));
+    }
+
+    @Test
+    public void shouldFindFirstChildByName() {
+        Segment segment = pathFactory.createSegment(firstChildName, 1);
+        ChildNode firstChild = children.getChild(segment);
+        assertThat(firstChild, is(notNullValue()));
+        assertThat(firstChild, is(sameInstance(this.firstChild)));
+        assertThat(firstChild.getUuid(), is(firstChildUuid));
+        assertThat(firstChild.getName(), is(firstChildName));
+        assertThat(firstChild.getSnsIndex(), is(1));
+        assertThat(firstChild.getSegment().getIndex(), is(1));
+        assertThat(firstChild.getSegment().getName(), is(firstChildName));
+    }
+
+    @Test
+    public void shouldImplementToString() {
+        children.toString();
+    }
+}


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

Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedChildrenTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedChildrenTest.java	                        (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedChildrenTest.java	2009-03-17 19:16:04 UTC (rev 780)
@@ -0,0 +1,150 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA is licensed
+ * to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.jcr.cache;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * 
+ */
+public class ChangedChildrenTest extends AbstractChildrenTest<ChangedChildren> {
+
+    private ImmutableChildren original;
+
+    @Override
+    @Before
+    public void beforeEach() {
+        super.beforeEach();
+
+        original = new ImmutableChildren(parentUuid);
+        firstChild = original.add(firstChildName, firstChildUuid, pathFactory);
+
+        children = new ChangedChildren(original);
+    }
+
+    @Test
+    public void shouldHaveCorrectSize() {
+        assertThat(children.size(), is(1));
+    }
+
+    @Test
+    public void shouldHaveSameContentsAsOriginal() {
+        assertSameContent(children, original);
+    }
+
+    @Test
+    public void shouldFindChildrenByName() {
+        Iterator<ChildNode> iter = children.getChildren(firstChildName);
+        assertThat(iter.hasNext(), is(true));
+        assertThat(iter.next(), is(sameInstance(firstChild)));
+        assertThat(iter.hasNext(), is(false));
+        try {
+            iter.next();
+            fail("Failed to throw exception");
+        } catch (NoSuchElementException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void shouldReturnSameInstanceFromWithoutIfSuppliedChildIsNotFound() {
+        ChildNode nonExistant = new ChildNode(UUID.randomUUID(), pathFactory.createSegment("some segment"));
+        assertThat(children.without(nonExistant, pathFactory), is(sameInstance((Children)children)));
+    }
+
+    @Test
+    public void shouldReturnEmptyChildrenFromWithoutIfOnlyChildIsRemoved() {
+        Children newChildren = children.without(firstChild, pathFactory);
+        assertThat(newChildren.size(), is(0));
+    }
+
+    @Test
+    public void shouldReturnSameInstanceFromWithIfSuppliedChildThatIsFoundInContainer() {
+        assertThat(children.with(firstChildName, firstChildUuid, pathFactory), is(sameInstance((Children)children)));
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldReturnIteratorThatDoesNotSupportRemoving() {
+        Iterator<ChildNode> iter = children.getChildren(firstChildName);
+        assertThat(iter.hasNext(), is(true));
+        assertThat(iter.next(), is(sameInstance(firstChild)));
+        iter.remove();
+    }
+
+    @Test
+    public void shouldReturnChangedChildrenFromWithoutIfSuppliedChildIsFound() {
+        ChildNode child2 = children.add(name("childB"), UUID.randomUUID(), pathFactory);
+        ChildNode child3 = children.add(name("childC"), UUID.randomUUID(), pathFactory);
+        ChildNode child4 = children.add(name("childA"), UUID.randomUUID(), pathFactory);
+        ChildNode child5 = children.add(name("childA"), UUID.randomUUID(), pathFactory);
+        ChildNode child6 = children.add(name("childD"), UUID.randomUUID(), pathFactory);
+
+        // Check that the children contains what we expect ...
+        assertChildNodes(children, firstChild, child2, child3, child4, child5, child6);
+        assertChildNodesWithName(children, "childA", firstChild, child4, child5);
+
+        // Remove 'child4' ...
+        Children result = children.without(child4, pathFactory);
+
+        // but the result should not have child4 ...
+        assertChildNodesWithName(result, "childA", firstChild, "childA");
+
+        // Now check that all the child nodes are in the result, in the expected order ...
+        assertChildNodes(result, firstChild, child2, child3, "childA", child6);
+    }
+
+    @Test
+    public void shouldReturnChangedChildrenFromWithIfSuppliedChildIsNotFound() {
+        // Make sure that children contains what we expect ...
+        assertChildNodes(children, firstChild);
+        assertChildNodesWithName(children, "childA", firstChild);
+
+        // Add a node ...
+        Children result = children.with(name("childB"), UUID.randomUUID(), pathFactory);
+        assertThat(result, is(sameInstance((Children)children)));
+        assertChildNodes(children, firstChild, "childB");
+        assertChildNodesWithName(children, "childA", firstChild);
+
+        // Add another node ...
+        result = children.with(name("childC"), UUID.randomUUID(), pathFactory);
+        assertThat(result, is(sameInstance((Children)children)));
+        assertChildNodes(children, firstChild, "childB", "childC");
+        assertChildNodesWithName(children, "childA", firstChild);
+
+        // Add another node ...
+        result = children.with(name("childA"), UUID.randomUUID(), pathFactory);
+        assertThat(result, is(sameInstance((Children)children)));
+        assertChildNodes(children, firstChild, "childB", "childC", "childA");
+        assertChildNodesWithName(children, "childA", firstChild, "childA");
+    }
+
+}


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

Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ImmutableChildrenTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ImmutableChildrenTest.java	                        (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ImmutableChildrenTest.java	2009-03-17 19:16:04 UTC (rev 780)
@@ -0,0 +1,141 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of 
+ * individual contributors.
+ *
+ * Unless otherwise indicated, all code in JBoss DNA is licensed
+ * to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.jcr.cache;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * 
+ */
+public class ImmutableChildrenTest extends AbstractChildrenTest<ImmutableChildren> {
+
+    @Override
+    @Before
+    public void beforeEach() {
+        super.beforeEach();
+
+        children = new ImmutableChildren(parentUuid);
+        firstChild = children.add(firstChildName, firstChildUuid, pathFactory);
+    }
+
+    @Test
+    public void shouldHaveCorrectSize() {
+        assertThat(children.size(), is(1));
+    }
+
+    @Test
+    public void shouldFindChildrenByName() {
+        Iterator<ChildNode> iter = children.getChildren(firstChildName);
+        assertThat(iter.hasNext(), is(true));
+        assertThat(iter.next(), is(sameInstance(firstChild)));
+        assertThat(iter.hasNext(), is(false));
+        try {
+            iter.next();
+            fail("Failed to throw exception");
+        } catch (NoSuchElementException e) {
+            // expected
+        }
+    }
+
+    @Test( expected = UnsupportedOperationException.class )
+    public void shouldReturnIteratorThatDoesNotSupportRemoving() {
+        Iterator<ChildNode> iter = children.getChildren(firstChildName);
+        assertThat(iter.hasNext(), is(true));
+        assertThat(iter.next(), is(sameInstance(firstChild)));
+        iter.remove();
+    }
+
+    @Test
+    public void shouldReturnEmptyChildrenFromWithoutIfOnlyChildIsRemoved() {
+        Children newChildren = children.without(firstChild, pathFactory);
+        assertThat(newChildren.size(), is(0));
+    }
+
+    @Test
+    public void shouldReturnChangedChildrenFromWithoutIfSuppliedChildIsFound() {
+        ChildNode child2 = children.add(name("childB"), UUID.randomUUID(), pathFactory);
+        ChildNode child3 = children.add(name("childC"), UUID.randomUUID(), pathFactory);
+        ChildNode child4 = children.add(name("childA"), UUID.randomUUID(), pathFactory);
+        ChildNode child5 = children.add(name("childA"), UUID.randomUUID(), pathFactory);
+        ChildNode child6 = children.add(name("childD"), UUID.randomUUID(), pathFactory);
+
+        // Check that the children contains what we expect ...
+        assertChildNodes(children, firstChild, child2, child3, child4, child5, child6);
+        assertChildNodesWithName(children, "childA", firstChild, child4, child5);
+
+        // Remove 'child4' ...
+        Children result = children.without(child4, pathFactory);
+
+        // the original should not have been changed ...
+        assertChildNodesWithName(children, "childA", firstChild, child4, child5);
+        // but the result should not have child4 ...
+        assertChildNodesWithName(result, "childA", firstChild, "childA");
+
+        // Now check that all the child nodes are still in the original, in the same order ...
+        assertChildNodes(children, firstChild, child2, child3, child4, child5, child6);
+
+        // Now check that all the child nodes are in the result, in the expected order ...
+        assertChildNodes(result, firstChild, child2, child3, "childA", child6);
+    }
+
+    @Test
+    public void shouldReturnChangedChildrenFromWithIfSuppliedChildIsNotFound() {
+        // Make sure that children contains what we expect ...
+        assertChildNodes(children, firstChild);
+        assertChildNodesWithName(children, "childA", firstChild);
+
+        // Add a node ...
+        ChangedChildren newChildren = children.with(name("childB"), UUID.randomUUID(), pathFactory);
+        assertChildNodes(newChildren, firstChild, "childB");
+        assertChildNodesWithName(newChildren, "childA", firstChild);
+        // And make sure 'children' hasn't changed ...
+        assertChildNodes(children, firstChild);
+        assertChildNodesWithName(children, "childA", firstChild);
+
+        // Add another node ...
+        newChildren = newChildren.with(name("childC"), UUID.randomUUID(), pathFactory);
+        assertChildNodes(newChildren, firstChild, "childB", "childC");
+        assertChildNodesWithName(newChildren, "childA", firstChild);
+        // And make sure 'children' hasn't changed ...
+        assertChildNodes(children, firstChild);
+        assertChildNodesWithName(children, "childA", firstChild);
+
+        // Add another node ...
+        newChildren = newChildren.with(name("childA"), UUID.randomUUID(), pathFactory);
+        assertChildNodes(newChildren, firstChild, "childB", "childC", "childA");
+        assertChildNodesWithName(newChildren, "childA", firstChild, "childA");
+        // And make sure 'children' hasn't changed ...
+        assertChildNodes(children, firstChild);
+        assertChildNodesWithName(children, "childA", firstChild);
+    }
+
+}


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




More information about the dna-commits mailing list