Author: rhauch
Date: 2009-03-18 12:54:54 -0400 (Wed, 18 Mar 2009)
New Revision: 782
Added:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/InternalChildren.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedNodeInfoTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingNames.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingUuids.java
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChildNode.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/ImmutableNodeInfo.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NodeInfo.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
Log:
DNA-194 Implement update JCR capability
Improved the mutable versions of the cached reprentations, and added a large number of
unit tests. The mutable objects should be ready to track adding/removing children and
adding/changing/removing properties. Making the SessionCache to use them is next.
Modified: 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 2009-03-18
04:38:44 UTC (rev 781)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java 2009-03-18
16:54:54 UTC (rev 782)
@@ -68,31 +68,34 @@
/**
* {@inheritDoc}
*
- * @see
org.jboss.dna.jcr.cache.ImmutableChildren#without(org.jboss.dna.jcr.cache.ChildNode,
- * org.jboss.dna.graph.property.PathFactory)
+ * @see org.jboss.dna.jcr.cache.ImmutableChildren#without(java.util.UUID,
org.jboss.dna.graph.property.PathFactory)
*/
@Override
- public ChangedChildren without( ChildNode child,
+ public ChangedChildren without( UUID childUuid,
PathFactory pathFactory ) {
- // Make sure this object contains the child ...
- if (!childrenByUuid.containsKey(child.getUuid())) {
+ // Remove the object that has the same UUID (regardless of the current SNS index)
...
+ ChildNode toBeRemoved = childrenByUuid.get(childUuid);
+ if (toBeRemoved == null) {
return this;
}
- // Remove the child fro this object, then adjust the remaining child node
instances that follow it ...
- Name childName = child.getName();
+ // Remove the child from this object, then adjust the remaining child node
instances that follow it ...
+ Name childName = toBeRemoved.getName();
List<ChildNode> childrenWithSameName = childrenByName.get(childName);
- int snsIndex = child.getSnsIndex();
+ int snsIndex = toBeRemoved.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 ...
+ ChildNode willBeRemoved = iter.next();
+ assert willBeRemoved == toBeRemoved;
+ childrenByUuid.remove(toBeRemoved.getUuid());
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));
+ childrenByUuid.put(newNext.getUuid(), newNext);
iter.set(newNext);
}
return this;
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java
(rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java 2009-03-18
16:54:54 UTC (rev 782)
@@ -0,0 +1,323 @@
+/*
+ * 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.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.Path.Segment;
+import org.jboss.dna.jcr.NodeDefinitionId;
+
+/**
+ * The information that describes a node. This is the information that is kept in the
cache.
+ * <p>
+ * Each instance maintains a reference to the original (usually immutable) NodeInfo
representation that was probably read from the
+ * repository.
+ */
+@Immutable
+public class ChangedNodeInfo implements NodeInfo {
+
+ protected static final PropertyInfo DELETED_PROPERTY = null;
+
+ /**
+ * A reference to the original representation of the node.
+ */
+ private final NodeInfo original;
+
+ /**
+ * The new parent for this node if it has been changed, or null if the parent has not
be changed.
+ */
+ private UUID newParent;
+
+ /**
+ * The updated children, or null if the children have not been changed from the
original's.
+ */
+ private ChangedChildren changedChildren;
+
+ /**
+ * This map, if it is non-null, contains the changed properties, overriding whatever
is in the original. If a property is
+ * removed from the original, an entry is added to this map with the name of the
removed property and a null PropertyInfo.
+ */
+ private Map<Name, PropertyInfo> changedProperties;
+
+ /**
+ * Create an immutable NodeInfo instance.
+ *
+ * @param original the original node information, may not be null
+ */
+ public ChangedNodeInfo( NodeInfo original ) {
+ assert original != null;
+ this.original = original;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.cache.NodeInfo#getOriginalLocation()
+ */
+ public Location getOriginalLocation() {
+ return original.getOriginalLocation();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.cache.NodeInfo#getUuid()
+ */
+ public UUID getUuid() {
+ return original.getUuid();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.cache.NodeInfo#getParent()
+ */
+ public UUID getParent() {
+ // Even if this is used for recording changes to the root node (which has no
parent),
+ // the root node cannot be moved to a different node (and no other node can be
moved to
+ // the root). Therefore, if this represents the root node, the original's
parent UUID will
+ // be the correct parent (null), and this representation will not need to have a
different
+ // (non-null) value.
+ if (newParent != null) return newParent;
+ return original.getParent();
+ }
+
+ /**
+ * Record that this node has been moved under a new parent. This method does
<i>not</i> change the ChildNode references in the
+ * old or new parent.
+ *
+ * @param parent the new parent, or null if the original's parent should be used
+ * @return the previous parent (either the original's or the last new parent);
may be null
+ */
+ public UUID setParent( UUID parent ) {
+ UUID result = newParent != null ? newParent : original.getParent(); // may still
be null
+ newParent = parent;
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.cache.NodeInfo#getPrimaryTypeName()
+ */
+ public Name getPrimaryTypeName() {
+ return original.getPrimaryTypeName();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.cache.NodeInfo#getDefinitionId()
+ */
+ public NodeDefinitionId getDefinitionId() {
+ return original.getDefinitionId();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.cache.NodeInfo#getChildren()
+ */
+ public Children getChildren() {
+ if (changedChildren != null) return changedChildren;
+ return original.getChildren();
+ }
+
+ /**
+ * Add a child to the children. This method does nothing if the child is already in
the children.
+ *
+ * @param childName the name of the child that is to be added; may not be null
+ * @param childUuid the UUID of the child that is to be added; may not be null
+ * @param factory the path factory that should be used to create a {@link Segment}
for the new {@link ChildNode} object
+ * @return the child node that was just added; never null
+ */
+ public ChildNode addChild( Name childName,
+ UUID childUuid,
+ PathFactory factory ) {
+ if (changedChildren == null) {
+ // We need to capture the original children as a changed contained ...
+ changedChildren = new ChangedChildren(original.getChildren());
+ }
+ return changedChildren.add(childName, childUuid, factory);
+ }
+
+ /**
+ * Remove a child from the children. This method only uses the child's UUID to
identify the contained ChildNode instance that
+ * should be removed.
+ * <p>
+ * Note that this method returns the new {@link Children} container, which is the
same as would be returned by
+ * {@link #getChildren()} called immediately after this method.
+ * </p>
+ *
+ * @param childUUID the UUID of the child that is to be removed; may not be null
+ * @param factory the path factory that should be used to create a {@link Segment}
for replacement {@link ChildNode} objects
+ * for nodes with the same name that and higher same-name-sibiling indexes.
+ * @return the Children object that has the modified children
+ */
+ public Children removeChild( UUID childUUID,
+ PathFactory factory ) {
+ if (changedChildren == null) {
+ // Create the changed children. First check whether there are 0 or 1 child
...
+ Children existing = original.getChildren();
+ int numExisting = existing.size();
+ if (numExisting == 0) {
+ // nothing to do, so return the original's children
+ return existing;
+ }
+ if (existing.getChild(childUUID) == null) {
+ // The requested child doesn't exist in the children, so return
silently ...
+ return existing;
+ }
+ if (numExisting == 1) {
+ // We're removing the only child in the original ...
+ changedChildren = new ChangedChildren(existing.getParentUuid());
+ return changedChildren;
+ }
+ // There is at least one child, so create the new children container ...
+ assert existing instanceof InternalChildren;
+ InternalChildren internal = (InternalChildren)existing;
+ changedChildren = internal.without(childUUID, factory);
+ } else {
+ changedChildren = changedChildren.without(childUUID, factory);
+ }
+ return changedChildren;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.cache.NodeInfo#hasProperties()
+ */
+ public boolean hasProperties() {
+ if (changedProperties == null) return original.hasProperties();
+ int numUnchanged = original.getPropertyCount();
+ int numChangedOrDeleted = changedProperties.size();
+ if (numUnchanged > numChangedOrDeleted) return true; // more unchanged than
could be deleted
+ // They could all be changed or deleted, so we need to find one changed property
...
+ for (Map.Entry<Name, PropertyInfo> entry : changedProperties.entrySet()) {
+ if (entry.getValue() != DELETED_PROPERTY) return true;
+ }
+ return false; // all properties must have been deleted ...
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.cache.NodeInfo#getPropertyCount()
+ */
+ public int getPropertyCount() {
+ int numUnchanged = original.getPropertyCount();
+ if (changedProperties == null) return numUnchanged;
+ return getPropertyNames().size();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.jcr.cache.NodeInfo#getPropertyNames()
+ */
+ public Set<Name> getPropertyNames() {
+ if (changedProperties != null) {
+ Set<Name> result = new
HashSet<Name>(original.getPropertyNames());
+ for (Map.Entry<Name, PropertyInfo> entry :
changedProperties.entrySet()) {
+ if (entry.getValue() != DELETED_PROPERTY) {
+ result.add(entry.getKey());
+ } else {
+ result.remove(entry.getKey());
+ }
+ }
+ return result; // don't make unmod wrapper, since we've already made
a copy ...
+ }
+ return original.getPropertyNames();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.jcr.cache.NodeInfo#getProperty(org.jboss.dna.graph.property.Name)
+ */
+ public PropertyInfo getProperty( Name name ) {
+ if (changedProperties != null && changedProperties.containsKey(name)) {
+ return changedProperties.get(name); // either the changed PropertyInfo, or
null if property was deleted
+ }
+ return original.getProperty(name);
+ }
+
+ public PropertyInfo setProperty( PropertyInfo newProperty ) {
+ Name name = newProperty.getPropertyName();
+ if (changedProperties == null) {
+ // There were no changes made yet ...
+
+ // Create the map of changed properties ...
+ changedProperties = new HashMap<Name, PropertyInfo>();
+ changedProperties.put(name, newProperty);
+
+ // And return the original property (or null if there was none) ...
+ return original.getProperty(name);
+ }
+ // The property may already have been changed, in which case we need to return
the changed one ...
+ if (changedProperties.containsKey(name)) {
+ PropertyInfo changed = changedProperties.put(name, null);
+ // The named property was indeed deleted ...
+ return changed;
+ }
+ // Otherwise, the property was not yet changed or deleted ...
+ PropertyInfo changed = original.getProperty(name);
+ changedProperties.put(name, newProperty);
+ return changed;
+ }
+
+ public PropertyInfo removeProperty( Name name ) {
+ if (changedProperties == null) {
+ // Make sure the property was in the original ...
+ PropertyInfo existing = original.getProperty(name);
+ if (existing == null) {
+ // The named property didn't exist in the original, nor was it added
and deleted in this object ...
+ return null;
+ }
+
+ // Create the map of changed properties ...
+ changedProperties = new HashMap<Name, PropertyInfo>();
+ changedProperties.put(name, DELETED_PROPERTY);
+ return existing;
+ }
+ // The property may already have been changed, in which case we need to return
the changed one ...
+ if (changedProperties.containsKey(name)) {
+ PropertyInfo changed = changedProperties.put(name, null);
+ // The named property was indeed deleted ...
+ return changed;
+ }
+ // Otherwise, the property was not yet changed or deleted ...
+ PropertyInfo changed = original.getProperty(name);
+ changedProperties.put(name, null);
+ return changed;
+ }
+}
Property changes on:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChildNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChildNode.java 2009-03-18 04:38:44
UTC (rev 781)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChildNode.java 2009-03-18 16:54:54
UTC (rev 782)
@@ -29,13 +29,19 @@
import org.jboss.dna.graph.property.Path;
/**
- *
+ * The representation of a child node. This is an immutable representation of a child
node within the collection of its siblings
+ * as the collection appeared at some point in time. This should be used as a guide to
determine how long to hold onto references.
+ * <p>
+ * For example, adding and removing children may affect the {@link #getSnsIndex()
same-name-sibling index} of the children, so
+ * these kinds of operations will result in the replacement of old ChildObject instances.
Therefore, clients should generally find
+ * the ChildNode instances in a {@link Children} container, use the ChildNode objects
quickly, then discard their references.
+ * </p>
+ * <p>
+ * There may be times when a client does wish to keep a representation of a ChildNode as
it appeared at some moment in time, and
+ * so it may want to hold onto references to ChildNode objects for longer durations. This
is fine, as long as it is understood
+ * that at some point the referenced ChildNode may no longer represent the current
state.
+ * </p>
*/
-/**
- * The information about a child node. This is designed to be found in the {@link
Children}, used quickly, and discarded. Clients
- * should not hold on to these objects, since any changes to the children involve
discarding the old ChildNode objects and
- * replacing them with new instances.
- */
@Immutable
public final class ChildNode {
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-18
04:38:44 UTC (rev 781)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/EmptyChildren.java 2009-03-18
16:54:54 UTC (rev 782)
@@ -35,7 +35,7 @@
* An immutable implementation of {@link Children}.
*/
@Immutable
-public final class EmptyChildren implements Children {
+public final class EmptyChildren implements Children, InternalChildren {
static final Iterator<ChildNode> EMPTY_ITERATOR = new
EmptyIterator<ChildNode>();
@@ -100,12 +100,10 @@
}
/**
- * Create another Children object that is equivalent to this node but with the
supplied child added.
+ * {@inheritDoc}
*
- * @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
+ * @see
org.jboss.dna.jcr.cache.InternalChildren#with(org.jboss.dna.graph.property.Name,
java.util.UUID,
+ * org.jboss.dna.graph.property.PathFactory)
*/
public ChangedChildren with( Name newChildName,
UUID newChildUuid,
@@ -116,14 +114,11 @@
}
/**
- * 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).
+ * {@inheritDoc}
*
- * @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
+ * @see org.jboss.dna.jcr.cache.InternalChildren#without(java.util.UUID,
org.jboss.dna.graph.property.PathFactory)
*/
- public ChangedChildren without( ChildNode child,
+ public ChangedChildren without( UUID childUuid,
PathFactory pathFactory ) {
return new ChangedChildren(this.parentUuid);
}
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-18
04:38:44 UTC (rev 781)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java 2009-03-18
16:54:54 UTC (rev 782)
@@ -42,7 +42,7 @@
* An immutable implementation of {@link Children}.
*/
@Immutable
-public class ImmutableChildren implements Children {
+public class ImmutableChildren implements Children, InternalChildren {
protected final UUID parentUuid;
protected final Map<UUID, ChildNode> childrenByUuid;
protected final ListMultimap<Name, ChildNode> childrenByName;
@@ -168,12 +168,10 @@
}
/**
- * Create another Children object that is equivalent to this node but with the
supplied child added.
+ * {@inheritDoc}
*
- * @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
+ * @see
org.jboss.dna.jcr.cache.InternalChildren#with(org.jboss.dna.graph.property.Name,
java.util.UUID,
+ * org.jboss.dna.graph.property.PathFactory)
*/
public ChangedChildren with( Name newChildName,
UUID newChildUuid,
@@ -184,19 +182,17 @@
}
/**
- * Create another Children object that is equivalent to this node but without the
supplied child.
+ * {@inheritDoc}
*
- * @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
+ * @see org.jboss.dna.jcr.cache.InternalChildren#without(java.util.UUID,
org.jboss.dna.graph.property.PathFactory)
*/
- public ChangedChildren without( ChildNode child,
+ public ChangedChildren without( UUID childUuid,
PathFactory pathFactory ) {
- if (this.childrenByUuid.containsKey(child.getUuid()) && this.size() == 1)
{
+ if (this.childrenByUuid.containsKey(childUuid) && this.size() == 1) {
return new ChangedChildren(this.parentUuid);
}
ChangedChildren newChildren = new ChangedChildren(this);
- return newChildren.without(child, pathFactory);
+ return newChildren.without(childUuid, pathFactory);
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableNodeInfo.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableNodeInfo.java 2009-03-18
04:38:44 UTC (rev 781)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableNodeInfo.java 2009-03-18
16:54:54 UTC (rev 782)
@@ -138,6 +138,15 @@
/**
* {@inheritDoc}
*
+ * @see org.jboss.dna.jcr.cache.NodeInfo#getPropertyCount()
+ */
+ public int getPropertyCount() {
+ return this.properties.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.jboss.dna.jcr.cache.NodeInfo#getPropertyNames()
*/
public Set<Name> getPropertyNames() {
Added: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/InternalChildren.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/InternalChildren.java
(rev 0)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/InternalChildren.java 2009-03-18
16:54:54 UTC (rev 782)
@@ -0,0 +1,57 @@
+/*
+ * 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.UUID;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.PathFactory;
+
+/**
+ * An internal interface for the {@link Children} implementations. Methods on this
interface are used internally and should not be
+ * used by components or clients.
+ */
+interface InternalChildren extends Children {
+
+ /**
+ * 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
+ */
+ ChangedChildren with( Name newChildName,
+ UUID newChildUuid,
+ PathFactory pathFactory );
+
+ /**
+ * Create another Children object that is equivalent to this node but without the
supplied child.
+ *
+ * @param childUuid the UUID of 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
+ */
+ ChangedChildren without( UUID childUuid,
+ PathFactory pathFactory );
+}
Property changes on:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/InternalChildren.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
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-18 04:38:44
UTC (rev 781)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/NodeInfo.java 2009-03-18 16:54:54
UTC (rev 782)
@@ -30,7 +30,7 @@
import org.jboss.dna.jcr.NodeDefinitionId;
/**
- * The information that describes a node. This is the information that is kept in the
cache.
+ * A representation of a node. This is the information that is kept in the cache.
*/
public interface NodeInfo {
@@ -60,7 +60,9 @@
public NodeDefinitionId getDefinitionId();
/**
- * Get the children for this node.
+ * Get the children for this node. Generally, clients should not hold onto the
returned object but instead should simply use
+ * it and discard the reference. This is because implementations are not required to
return the same instance with each call
+ * (although immutable implementations are expected to always return the same
instance).
*
* @return the immutable children; never null but possibly empty
*/
@@ -74,6 +76,13 @@
public boolean hasProperties();
/**
+ * Return the number of properties on this node.
+ *
+ * @return the number of properties; never negative
+ */
+ public int getPropertyCount();
+
+ /**
* Get the names of the properties that are owned by this node.
*
* @return the unmodifiable set of property names
Modified: 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 2009-03-18
04:38:44 UTC (rev 781)
+++
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedChildrenTest.java 2009-03-18
16:54:54 UTC (rev 782)
@@ -78,12 +78,12 @@
@Test
public void shouldReturnSameInstanceFromWithoutIfSuppliedChildIsNotFound() {
ChildNode nonExistant = new ChildNode(UUID.randomUUID(),
pathFactory.createSegment("some segment"));
- assertThat(children.without(nonExistant, pathFactory),
is(sameInstance((Children)children)));
+ assertThat(children.without(nonExistant.getUuid(), pathFactory),
is(sameInstance((Children)children)));
}
@Test
public void shouldReturnEmptyChildrenFromWithoutIfOnlyChildIsRemoved() {
- Children newChildren = children.without(firstChild, pathFactory);
+ Children newChildren = children.without(firstChild.getUuid(), pathFactory);
assertThat(newChildren.size(), is(0));
}
@@ -113,7 +113,7 @@
assertChildNodesWithName(children, "childA", firstChild, child4,
child5);
// Remove 'child4' ...
- Children result = children.without(child4, pathFactory);
+ Children result = children.without(child4.getUuid(), pathFactory);
// but the result should not have child4 ...
assertChildNodesWithName(result, "childA", firstChild,
"childA");
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedNodeInfoTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedNodeInfoTest.java
(rev 0)
+++
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedNodeInfoTest.java 2009-03-18
16:54:54 UTC (rev 782)
@@ -0,0 +1,629 @@
+/*
+ * 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.IsNot.not;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
+import static org.hamcrest.core.IsSame.sameInstance;
+import static org.jboss.dna.jcr.cache.IsNodeInfoWithChildrenHavingNames.hasChild;
+import static org.jboss.dna.jcr.cache.IsNodeInfoWithChildrenHavingNames.hasChildren;
+import static org.jboss.dna.jcr.cache.IsNodeInfoWithChildrenHavingUuids.hasChild;
+import static org.jboss.dna.jcr.cache.IsNodeInfoWithChildrenHavingUuids.hasChildren;
+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.Map;
+import java.util.Set;
+import java.util.UUID;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.PathFactory;
+import org.jboss.dna.graph.property.Path.Segment;
+import org.jboss.dna.jcr.NodeDefinitionId;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class ChangedNodeInfoTest {
+
+ private ExecutionContext context;
+ private PathFactory pathFactory;
+ private NodeInfo original;
+ private UUID uuid;
+ private Name primaryTypeName;
+ private Location location;
+ private NodeDefinitionId definitionId;
+ private ChangedChildren children;
+ private Map<Name, PropertyInfo> properties;
+ private ChangedNodeInfo changes;
+
+ @Before
+ public void beforeEach() {
+ context = new ExecutionContext();
+ context.getNamespaceRegistry().register("acme",
"http://example.com/acme");
+ pathFactory = context.getValueFactories().getPathFactory();
+
+ // Set up the original ...
+ uuid = UUID.randomUUID();
+ location = Location.create(uuid);
+ primaryTypeName = name("acme:geniusType");
+ definitionId = new NodeDefinitionId(name("acme:geniusContainerType"),
name("acme:geniuses"));
+ children = new ChangedChildren(uuid);
+ properties = new HashMap<Name, PropertyInfo>();
+ original = new ImmutableNodeInfo(location, primaryTypeName, definitionId, uuid,
children, properties);
+
+ // Create the changed node representation ...
+ changes = new ChangedNodeInfo(original);
+ }
+
+ protected Name name( String name ) {
+ return context.getValueFactories().getNameFactory().create(name);
+ }
+
+ protected Segment segment( String segment ) {
+ return pathFactory.createSegment(segment);
+ }
+
+ /**
+ * Utility to set a property to the original node representation. This will replace
any existing property with the same name.
+ *
+ * @param name the name of the property; may not be null
+ * @return the new property representation; never null
+ */
+ protected PropertyInfo makePropertyInOriginal( String name ) {
+ Name propName = name(name);
+ PropertyInfo propertyInfo = mock(PropertyInfo.class);
+ stub(propertyInfo.getPropertyName()).toReturn(propName);
+ properties.put(propName, propertyInfo);
+ return propertyInfo;
+ }
+
+ /**
+ * Utility to change a property in the changed representation.
+ *
+ * @param name the name of the property to change; may not be null
+ * @return the new property; never null
+ */
+ protected PropertyInfo setPropertyInChanged( String name ) {
+ Name propName = name(name);
+ PropertyInfo propertyInfo = mock(PropertyInfo.class);
+ stub(propertyInfo.getPropertyName()).toReturn(propName);
+ changes.setProperty(propertyInfo);
+ return propertyInfo;
+ }
+
+ protected ChildNode makeChildInOriginal( String childName ) {
+ ChildNode newChild = children.add(name(childName), UUID.randomUUID(),
pathFactory);
+ return newChild;
+ }
+
+ protected ChildNode addChildInChanged( String childName ) {
+ ChildNode newChild = changes.addChild(name(childName), UUID.randomUUID(),
pathFactory);
+ // Make sure that the 'changes' object no longer returns the original
object's children object
+ assertThat(changes.getChildren(),
is(not(sameInstance(original.getChildren()))));
+ return newChild;
+ }
+
+ protected void removeChildFromChanged( ChildNode child ) {
+ // Verify that a child node with the supplied UUID is contained.
+ // Note that it may not be the same ChildNode instance if another SNS node with
smaller index was removed
+ assertThat(changes.getChildren().getChild(child.getUuid()), is(notNullValue()));
+ // Now remove the child, making sure the result is the same as the next
'getChildren()' call ...
+ assertThat(changes.removeChild(child.getUuid(), pathFactory),
is(sameInstance(changes.getChildren())));
+ // Verify it no longer exists ...
+ assertThat(changes.getChildren().getChild(child.getUuid()), is(nullValue()));
+ }
+
+ @Test
+ public void shouldHaveLocationFromOriginal() {
+ assertThat(changes.getOriginalLocation(), is(sameInstance(location)));
+ }
+
+ @Test
+ public void shouldHaveParentUuidFromOriginal() {
+ assertThat(changes.getParent(), is(sameInstance(uuid)));
+ }
+
+ @Test
+ public void shouldHavePrimaryTypeNameFromOriginal() {
+ assertThat(changes.getPrimaryTypeName(), is(sameInstance(primaryTypeName)));
+ }
+
+ @Test
+ public void shouldHaveNodeDefinitionIdFromOriginal() {
+ assertThat(changes.getDefinitionId(), is(sameInstance(definitionId)));
+ }
+
+ @Test
+ public void shouldHaveChildrenFromOriginal() {
+ assertThat(changes.getChildren(), is(sameInstance((Children)children)));
+
+ ChildNode childA = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(1));
+ assertThat(changes.getChildren().getChild(childA.getUuid()),
is(sameInstance(childA)));
+ assertThat(changes.getChildren(), hasChild(segment("childA[1]")));
+ assertThat(changes.getChildren(), hasChild(childA.getUuid()));
+ }
+
+ @Test
+ public void shouldHaveChildrenAfterAddingChild() {
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Add child ...
+ ChildNode childA3 = addChildInChanged("childA");
+
+ // Verify that all children are there in the proper order ...
+ assertThat(changes.getChildren().size(), is(4));
+ assertThat(changes.getChildren(), hasChildren(segment("childA[1]"),
+ segment("childB[1]"),
+ segment("childA[2]"),
+ segment("childA[3]")));
+ assertThat(changes.getChildren(), hasChildren(childA1.getUuid(),
childB1.getUuid(), childA2.getUuid(), childA3.getUuid()));
+ assertThat(changes.getChildren(), hasItems(childA1, childB1, childA2, childA3));
+ }
+
+ @Test
+ public void shouldHaveChildrenAfterAddingMultipleChildren() {
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Add some children in the changed representation ...
+ ChildNode childA3 = addChildInChanged("childA");
+ ChildNode childC1 = addChildInChanged("childC");
+ ChildNode childC2 = addChildInChanged("childC");
+
+ // Verify that all children are there in the proper order ...
+ assertThat(changes.getChildren().size(), is(6));
+ assertThat(changes.getChildren(), hasChildren(segment("childA[1]"),
+ segment("childB[1]"),
+ segment("childA[2]"),
+ segment("childA[3]"),
+ segment("childC[1]"),
+ segment("childC[2]")));
+ assertThat(changes.getChildren(), hasChildren(childA1.getUuid(),
+ childB1.getUuid(),
+ childA2.getUuid(),
+ childA3.getUuid(),
+ childC1.getUuid(),
+ childC2.getUuid()));
+ assertThat(changes.getChildren(), hasItems(childA1, childB1, childA2, childA3,
childC1, childC2));
+ }
+
+ @Test
+ public void shouldHaveChildrenAfterAddingMultipleChildrenAndRemovingOthers() {
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Add some children in the changed representation ...
+ ChildNode childA3 = addChildInChanged("childA");
+ ChildNode childC1 = addChildInChanged("childC");
+ ChildNode childC2 = addChildInChanged("childC");
+
+ // Delete a child that was added and another that was an original ...
+ removeChildFromChanged(childC1);
+ removeChildFromChanged(childA2);
+
+ // Verify that all children are there in the proper order ...
+ assertThat(changes.getChildren().size(), is(4));
+ assertThat(changes.getChildren(), hasChildren(segment("childA[1]"),
+ segment("childB[1]"),
+ segment("childA[2]"),
+ segment("childC[1]")));
+ assertThat(changes.getChildren(), hasChildren(childA1.getUuid(),
childB1.getUuid(), childA3.getUuid(), childC2.getUuid()));
+ }
+
+ @Test
+ public void
shouldHaveChildrenAfterAddingMultipleChildrenAndThenRemovingThoseJustAdded() {
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Add some children in the changed representation ...
+ ChildNode childA3 = addChildInChanged("childA");
+ ChildNode childC1 = addChildInChanged("childC");
+ ChildNode childC2 = addChildInChanged("childC");
+
+ // Delete a child that was added and another that was an original...
+ removeChildFromChanged(childA3);
+ removeChildFromChanged(childC1); // causes replacement of 'childC2' with
lower SNS index
+ removeChildFromChanged(childC2);
+
+ // Verify that all children are there in the proper order ...
+ assertThat(changes.getChildren().size(), is(3));
+ assertThat(changes.getChildren(), hasChildren(segment("childA[1]"),
segment("childB[1]"), segment("childA[2]")));
+ assertThat(changes.getChildren(), hasChildren(childA1.getUuid(),
childB1.getUuid(), childA2.getUuid()));
+
+ // Do it again, but change the order of delete to delete from the back ...
+
+ // Add some children in the changed representation ...
+ childA3 = addChildInChanged("childA");
+ childC1 = addChildInChanged("childC");
+ childC2 = addChildInChanged("childC");
+
+ // Delete a child that was added and another that was an original ...
+ removeChildFromChanged(childC2);
+ removeChildFromChanged(childC1);
+ removeChildFromChanged(childA3);
+
+ // Verify that all children are there in the proper order ...
+ assertThat(changes.getChildren().size(), is(3));
+ assertThat(changes.getChildren(), hasChildren(segment("childA[1]"),
segment("childB[1]"), segment("childA[2]")));
+ assertThat(changes.getChildren(), hasChildren(childA1.getUuid(),
childB1.getUuid(), childA2.getUuid()));
+
+ }
+
+ @Test
+ public void shouldHaveChildrenAfterDeletingChild() {
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Delete a child that was added and another that was an original ...
+ removeChildFromChanged(childA1);
+
+ // Verify that all children are there in the proper order ...
+ assertThat(changes.getChildren().size(), is(2));
+ assertThat(changes.getChildren(), hasChildren(segment("childB[1]"),
segment("childA[1]")));
+ assertThat(changes.getChildren(), hasChildren(childB1.getUuid(),
childA2.getUuid()));
+ }
+
+ @Test
+ public void shouldHaveChildrenAfterDeletingMultipleChildren() {
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Delete a child that was added and another that was an original ...
+ removeChildFromChanged(childA1);
+ removeChildFromChanged(childA2);
+
+ // Verify that all children are there in the proper order ...
+ assertThat(changes.getChildren().size(), is(1));
+ assertThat(changes.getChildren(), hasChildren(segment("childB[1]")));
+ assertThat(changes.getChildren(), hasChildren(childB1.getUuid()));
+ }
+
+ @Test
+ public void shouldHaveChildrenAfterDeletingAllChildrenFromTheFirsttChildToTheLast()
{
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Delete all children, from the front to the back ...
+ removeChildFromChanged(childA1); // causes replacement of 'childA2' with
lower SNS index
+ removeChildFromChanged(childA2);
+ removeChildFromChanged(childB1);
+
+ // Verify that all children have been removed ...
+ assertThat(changes.getChildren().size(), is(0));
+ }
+
+ @Test
+ public void shouldHaveChildrenAfterDeletingAllChildrenFromTheLastChildToTheFirst() {
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Delete all children, from the back to the front ...
+ removeChildFromChanged(childA2);
+ removeChildFromChanged(childB1);
+ removeChildFromChanged(childA1);
+
+ // Verify that all children have been removed ...
+ assertThat(changes.getChildren().size(), is(0));
+ }
+
+ @Test
+ public void
shouldHaveChildrenAfterAddingSomeChildrenThenDeletingAllChildrenFromTheFirstChildToTheLast()
{
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Add some children in the changed representation ...
+ ChildNode childA3 = addChildInChanged("childA");
+ ChildNode childC1 = addChildInChanged("childC");
+ ChildNode childC2 = addChildInChanged("childC");
+
+ // Delete all children, from the front to the back ...
+ removeChildFromChanged(childA3);
+ removeChildFromChanged(childC1); // causes replacement of 'childC2' with
lower SNS index
+ removeChildFromChanged(childC2);
+ removeChildFromChanged(childA1); // causes replacement of 'childA2' with
lower SNS index
+ removeChildFromChanged(childB1);
+ removeChildFromChanged(childA2);
+
+ // Verify that all children have been removed ...
+ assertThat(changes.getChildren().size(), is(0));
+ }
+
+ @Test
+ public void
shouldHaveChildrenAfterAddingSomeChildrenThenDeletingAllChildrenFromTheLastChildToTheFirst()
{
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Add some children in the changed representation ...
+ ChildNode childA3 = addChildInChanged("childA");
+ ChildNode childC1 = addChildInChanged("childC");
+ ChildNode childC2 = addChildInChanged("childC");
+
+ // Delete all children, from the back to the front ...
+ removeChildFromChanged(childC2);
+ removeChildFromChanged(childC1);
+ removeChildFromChanged(childA3);
+ removeChildFromChanged(childA2);
+ removeChildFromChanged(childB1);
+ removeChildFromChanged(childA1);
+
+ // Verify that all children have been removed ...
+ assertThat(changes.getChildren().size(), is(0));
+ }
+
+ @Test
+ public void shouldHaveChildrenAfterReorderingChildren() {
+
+ }
+
+ @Test
+ @SuppressWarnings( "unused" )
+ public void
shouldNotRemoveFromNodeInfoWithNoChildChangesAChildThatMatchesSegmentButNotUuid() {
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Create a bogus node that has a new UUID but with the same segment as
'childA3' ...
+ Children before = changes.getChildren();
+ int beforeSize = before.size();
+ Children after = changes.removeChild(UUID.randomUUID(), pathFactory);
+ assertThat(after.size(), is(beforeSize));
+ assertThat(after, is(sameInstance(before)));
+ assertThat(after, is(sameInstance(changes.getChildren())));
+ }
+
+ @Test
+ @SuppressWarnings( "unused" )
+ public void
shouldNotRemoveFromNodeInfoWithSomeChildChangesAChildThatMatchesSegmentButNotUuid() {
+ // Set up the original ...
+ ChildNode childA1 = makeChildInOriginal("childA");
+ ChildNode childB1 = makeChildInOriginal("childB");
+ ChildNode childA2 = makeChildInOriginal("childA");
+ assertThat(changes.getChildren().size(), is(3));
+
+ // Add some children in the changed representation ...
+ ChildNode childA3 = addChildInChanged("childA");
+ ChildNode childC1 = addChildInChanged("childC");
+ ChildNode childC2 = addChildInChanged("childC");
+
+ // Create a bogus node that has a new UUID but with the same segment as
'childA3' ...
+ Children before = changes.getChildren();
+ int beforeSize = before.size();
+ Children after = changes.removeChild(UUID.randomUUID(), pathFactory);
+ assertThat(after.size(), is(beforeSize));
+ assertThat(after, is(sameInstance(before)));
+ assertThat(after, is(sameInstance(changes.getChildren())));
+ }
+
+ @Test
+ public void shouldFindPropertyThatHasNotBeenModifiedButIsInOriginal() {
+ PropertyInfo propertyInfo = makePropertyInOriginal("test");
+ assertThat(changes.getProperty(name("test")),
is(sameInstance(propertyInfo)));
+ }
+
+ @Test
+ public void shouldFindPropertyThatHasBeenModifiedFromOriginal() {
+ PropertyInfo propertyInfo = makePropertyInOriginal("test");
+ assertThat(changes.getProperty(name("test")),
is(sameInstance(propertyInfo)));
+
+ // Modify the property ...
+ PropertyInfo newPropertyInfo = mock(PropertyInfo.class);
+ stub(newPropertyInfo.getPropertyName()).toReturn(name("test"));
+ PropertyInfo previous = changes.setProperty(newPropertyInfo);
+ assertThat(previous, is(sameInstance(propertyInfo)));
+
+ // Verify we can find the new property ...
+ assertThat(changes.getProperty(name("test")),
is(sameInstance(newPropertyInfo)));
+ }
+
+ @Test
+ public void shouldNotFindPropertyThatHasBeenDeletedFromOriginal() {
+ PropertyInfo propertyInfo = makePropertyInOriginal("test");
+ assertThat(changes.getProperty(name("test")),
is(sameInstance(propertyInfo)));
+
+ // Delete the property ...
+ PropertyInfo previous = changes.removeProperty(name("test"));
+ assertThat(previous, is(sameInstance(propertyInfo)));
+
+ // Verify we can not find the new property ...
+ assertThat(changes.getProperty(name("test")), is(nullValue()));
+ }
+
+ @Test
+ public void shouldNotFindPropertyThatIsNotInOriginal() {
+ assertThat(changes.getProperty(name("test")), is(nullValue()));
+
+ makePropertyInOriginal("test");
+ assertThat(changes.getProperty(name("nonExistant")), is(nullValue()));
+ }
+
+ @Test
+ public void shouldFindAllPropertyNamesWhenChangedNodeHasNoChangedProperties() {
+ PropertyInfo propA = makePropertyInOriginal("propA");
+ PropertyInfo propB = makePropertyInOriginal("propB");
+ PropertyInfo propC = makePropertyInOriginal("propC");
+ PropertyInfo propD = makePropertyInOriginal("propD");
+ Set<Name> names = changes.getPropertyNames();
+ assertThat(names.size(), is(4));
+ assertThat(names, hasItems(propA.getPropertyName(),
+ propB.getPropertyName(),
+ propC.getPropertyName(),
+ propD.getPropertyName()));
+ }
+
+ @Test
+ public void shouldFindAllPropertyNamesWhenChangedNodeHasDeletedAllProperties() {
+ PropertyInfo propA = makePropertyInOriginal("propA");
+ PropertyInfo propB = makePropertyInOriginal("propB");
+ PropertyInfo propC = makePropertyInOriginal("propC");
+ PropertyInfo propD = makePropertyInOriginal("propD");
+ // Remove all properties ...
+ assertThat(changes.removeProperty(propA.getPropertyName()),
is(sameInstance(propA)));
+ assertThat(changes.removeProperty(propB.getPropertyName()),
is(sameInstance(propB)));
+ assertThat(changes.removeProperty(propC.getPropertyName()),
is(sameInstance(propC)));
+ assertThat(changes.removeProperty(propD.getPropertyName()),
is(sameInstance(propD)));
+ // Now ask for names
+ Set<Name> names = changes.getPropertyNames();
+ assertThat(names.size(), is(0));
+ }
+
+ @Test
+ public void shouldFindAllPropertyNamesWhenChangedNodeHasDeletedSomeProperties() {
+ PropertyInfo propA = makePropertyInOriginal("propA");
+ PropertyInfo propB = makePropertyInOriginal("propB");
+ PropertyInfo propC = makePropertyInOriginal("propC");
+ PropertyInfo propD = makePropertyInOriginal("propD");
+ // Remove some properties ...
+ assertThat(changes.removeProperty(propB.getPropertyName()),
is(sameInstance(propB)));
+ assertThat(changes.removeProperty(propD.getPropertyName()),
is(sameInstance(propD)));
+ // Now ask for names
+ Set<Name> names = changes.getPropertyNames();
+ assertThat(names.size(), is(2));
+ assertThat(names, hasItems(propA.getPropertyName(), propC.getPropertyName()));
+ }
+
+ @Test
+ @SuppressWarnings( "unused" )
+ public void shouldFindAllPropertyNamesWhenChangedNodeHasChangedSomeProperties() {
+ PropertyInfo propA = makePropertyInOriginal("propA");
+ PropertyInfo propB = makePropertyInOriginal("propB");
+ PropertyInfo propC = makePropertyInOriginal("propC");
+ PropertyInfo propD = makePropertyInOriginal("propD");
+ // Change some properties ...
+ PropertyInfo propB2 = setPropertyInChanged("propB");
+ PropertyInfo propC2 = setPropertyInChanged("propC");
+ // Now ask for names
+ Set<Name> names = changes.getPropertyNames();
+ assertThat(names.size(), is(4));
+ assertThat(names, hasItems(propA.getPropertyName(),
+ propB2.getPropertyName(),
+ propC2.getPropertyName(),
+ propD.getPropertyName()));
+ }
+
+ @Test
+ @SuppressWarnings( "unused" )
+ public void shouldFindAllPropertyNamesWhenChangedNodeHasAddedSomeProperties() {
+ PropertyInfo propA = makePropertyInOriginal("propA");
+ PropertyInfo propB = makePropertyInOriginal("propB");
+ PropertyInfo propC = makePropertyInOriginal("propC");
+ PropertyInfo propD = makePropertyInOriginal("propD");
+ // Add some properties ...
+ PropertyInfo propE = setPropertyInChanged("propE");
+ PropertyInfo propF = setPropertyInChanged("propF");
+ PropertyInfo propG = setPropertyInChanged("propG");
+ // Now ask for names
+ Set<Name> names = changes.getPropertyNames();
+ assertThat(names.size(), is(7));
+ assertThat(names, hasItems(propA.getPropertyName(),
+ propB.getPropertyName(),
+ propC.getPropertyName(),
+ propD.getPropertyName(),
+ propE.getPropertyName(),
+ propF.getPropertyName()));
+ }
+
+ @Test
+ @SuppressWarnings( "unused" )
+ public void
shouldFindAllPropertyNamesWhenChangedNodeHasChangedAndDeletedAndAddedSomeProperties() {
+ PropertyInfo propA = makePropertyInOriginal("propA");
+ PropertyInfo propB = makePropertyInOriginal("propB");
+ PropertyInfo propC = makePropertyInOriginal("propC");
+ PropertyInfo propD = makePropertyInOriginal("propD");
+ // Change some properties ...
+ PropertyInfo propB2 = setPropertyInChanged("propB");
+ PropertyInfo propC2 = setPropertyInChanged("propC");
+ // Add some properties ...
+ PropertyInfo propE = setPropertyInChanged("propE");
+ // Remove some properties ...
+ assertThat(changes.removeProperty(propB2.getPropertyName()),
is(sameInstance(propB2)));
+ assertThat(changes.removeProperty(propD.getPropertyName()),
is(sameInstance(propD)));
+ // Now ask for names
+ Set<Name> names = changes.getPropertyNames();
+ assertThat(names.size(), is(3));
+ assertThat(names, hasItems(propA.getPropertyName(), propC2.getPropertyName(),
propE.getPropertyName()));
+ }
+
+ @Test
+ @SuppressWarnings( "unused" )
+ public void
shouldFindAllPropertyNamesWhenChangedNodeHasChangedAndDeletedAllProperties() {
+ PropertyInfo propA = makePropertyInOriginal("propA");
+ PropertyInfo propB = makePropertyInOriginal("propB");
+ PropertyInfo propC = makePropertyInOriginal("propC");
+ PropertyInfo propD = makePropertyInOriginal("propD");
+ // Change some properties ...
+ PropertyInfo propB2 = setPropertyInChanged("propB");
+ PropertyInfo propC2 = setPropertyInChanged("propC");
+ // Remove all properties ...
+ assertThat(changes.removeProperty(propA.getPropertyName()),
is(sameInstance(propA)));
+ assertThat(changes.removeProperty(propB2.getPropertyName()),
is(sameInstance(propB2)));
+ assertThat(changes.removeProperty(propC2.getPropertyName()),
is(sameInstance(propC2)));
+ assertThat(changes.removeProperty(propD.getPropertyName()),
is(sameInstance(propD)));
+ // Now ask for names
+ Set<Name> names = changes.getPropertyNames();
+ assertThat(names.size(), is(0));
+ }
+
+}
Property changes on:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ChangedNodeInfoTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: 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 2009-03-18
04:38:44 UTC (rev 781)
+++
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/ImmutableChildrenTest.java 2009-03-18
16:54:54 UTC (rev 782)
@@ -76,7 +76,7 @@
@Test
public void shouldReturnEmptyChildrenFromWithoutIfOnlyChildIsRemoved() {
- Children newChildren = children.without(firstChild, pathFactory);
+ Children newChildren = children.without(firstChild.getUuid(), pathFactory);
assertThat(newChildren.size(), is(0));
}
@@ -93,7 +93,7 @@
assertChildNodesWithName(children, "childA", firstChild, child4,
child5);
// Remove 'child4' ...
- Children result = children.without(child4, pathFactory);
+ Children result = children.without(child4.getUuid(), pathFactory);
// the original should not have been changed ...
assertChildNodesWithName(children, "childA", firstChild, child4,
child5);
Added:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingNames.java
===================================================================
---
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingNames.java
(rev 0)
+++
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingNames.java 2009-03-18
16:54:54 UTC (rev 782)
@@ -0,0 +1,84 @@
+/*
+ * 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.jcr.cache;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.hamcrest.Description;
+import org.hamcrest.Factory;
+import org.hamcrest.Matcher;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.basic.BasicPathSegment;
+import org.junit.matchers.IsCollectionContaining;
+import org.junit.matchers.TypeSafeMatcher;
+
+/**
+ * A JUnit {@link TypeSafeMatcher matcher} that can be used to assert that a NodeInfo (or
other
+ * <code>Iterable<ChildNode></code>) has {@link ChildNode}
instances with specific {@link ChildNode#getSegment() names}.
+ */
+public class IsNodeInfoWithChildrenHavingNames extends TypeSafeMatcher<Children> {
+ private final Matcher<Iterable<Path.Segment>> childMatcher;
+
+ public IsNodeInfoWithChildrenHavingNames( Matcher<Iterable<Path.Segment>>
childMatcher ) {
+ this.childMatcher = childMatcher;
+ }
+
+ @Override
+ public boolean matchesSafely( Children children ) {
+ List<Path.Segment> childSegments = new
ArrayList<Path.Segment>(children.size());
+ for (ChildNode child : children) {
+ childSegments.add(child.getSegment());
+ }
+ return childMatcher.matches(childSegments);
+ }
+
+ public void describeTo( Description description ) {
+ description.appendText("children").appendDescriptionOf(childMatcher);
+ }
+
+ @Factory
+ public static IsNodeInfoWithChildrenHavingNames hasChild( Name name,
+ int sameNameSiblingIndex )
{
+ Path.Segment segment = new BasicPathSegment(name, sameNameSiblingIndex);
+ return new
IsNodeInfoWithChildrenHavingNames(IsCollectionContaining.hasItem(segment));
+ }
+
+ @Factory
+ public static IsNodeInfoWithChildrenHavingNames hasChild( Path.Segment child ) {
+ return new
IsNodeInfoWithChildrenHavingNames(IsCollectionContaining.hasItem(child));
+ }
+
+ @Factory
+ public static IsNodeInfoWithChildrenHavingNames hasChildren( Path.Segment...
childSegments ) {
+ return new
IsNodeInfoWithChildrenHavingNames(IsCollectionContaining.hasItems(childSegments));
+ }
+
+ @Factory
+ public static IsNodeInfoWithChildrenHavingNames isEmpty() {
+ Path.Segment[] childSegments = new Path.Segment[] {};
+ return new
IsNodeInfoWithChildrenHavingNames(IsCollectionContaining.hasItems(childSegments));
+ }
+
+}
Property changes on:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingNames.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingUuids.java
===================================================================
---
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingUuids.java
(rev 0)
+++
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingUuids.java 2009-03-18
16:54:54 UTC (rev 782)
@@ -0,0 +1,75 @@
+/*
+ * 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.jcr.cache;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import org.hamcrest.Description;
+import org.hamcrest.Factory;
+import org.hamcrest.Matcher;
+import org.junit.matchers.IsCollectionContaining;
+import org.junit.matchers.TypeSafeMatcher;
+
+/**
+ * A JUnit {@link TypeSafeMatcher matcher} that can be used to assert that a NodeInfo (or
other
+ * <code>Iterable<ChildNode></code>) has {@link ChildNode}
instances with specific {@link ChildNode#getUuid() UUIDs}.
+ */
+public class IsNodeInfoWithChildrenHavingUuids extends TypeSafeMatcher<Children> {
+ private final Matcher<Iterable<UUID>> childMatcher;
+
+ public IsNodeInfoWithChildrenHavingUuids( Matcher<Iterable<UUID>>
childMatcher ) {
+ this.childMatcher = childMatcher;
+ }
+
+ @Override
+ public boolean matchesSafely( Children children ) {
+ List<UUID> childSegments = new ArrayList<UUID>(children.size());
+ for (ChildNode child : children) {
+ childSegments.add(child.getUuid());
+ }
+ return childMatcher.matches(childSegments);
+ }
+
+ public void describeTo( Description description ) {
+ description.appendText("children with
UUIDs").appendDescriptionOf(childMatcher);
+ }
+
+ @Factory
+ public static IsNodeInfoWithChildrenHavingUuids hasChild( UUID uuid ) {
+ return new
IsNodeInfoWithChildrenHavingUuids(IsCollectionContaining.hasItem(uuid));
+ }
+
+ @Factory
+ public static IsNodeInfoWithChildrenHavingUuids hasChildren( UUID... uuids ) {
+ return new
IsNodeInfoWithChildrenHavingUuids(IsCollectionContaining.hasItems(uuids));
+ }
+
+ @Factory
+ public static IsNodeInfoWithChildrenHavingUuids isEmpty() {
+ UUID[] uuids = new UUID[] {};
+ return new
IsNodeInfoWithChildrenHavingUuids(IsCollectionContaining.hasItems(uuids));
+ }
+
+}
Property changes on:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/cache/IsNodeInfoWithChildrenHavingUuids.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain