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.
+ */
+@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