You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by md...@apache.org on 2013/04/24 12:37:52 UTC

svn commit: r1471355 [1/2] - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/core/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/strategy/ o...

Author: mduerig
Date: Wed Apr 24 10:37:51 2013
New Revision: 1471355

URL: http://svn.apache.org/r1471355
Log:
OAK-781: Clarify / fix effects of MISSING_NODE as base state of NodeBuilder
rework MemoryNodeBuilder:
- promote MutableNodeState to top level package private class
- separate state tracking and hierarchy tracking between MemoryNodeBuilder and MutableNodeState, respectively
- rename NodeBuilder methods to match those of NodeState

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MutableNodeState.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecuredNodeRebaseDiff.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/MergingNodeStateDiff.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/strategy/ContentMirrorStoreStrategy.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/ModifiedNodeState.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MergeDiff.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractRebaseDiff.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ConflictAnnotatingRebaseDiff.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeBuilderTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilderTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompareAgainstBaseStateTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java
    jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/ReadOnlyOakDirectory.java
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHookTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecuredNodeRebaseDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecuredNodeRebaseDiff.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecuredNodeRebaseDiff.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecuredNodeRebaseDiff.java Wed Apr 24 10:37:51 2013
@@ -96,7 +96,7 @@ class SecuredNodeRebaseDiff extends Abst
         // FIXME (OAK-709) after might be a secured node instead of the underlying non secured node.
         // Pushing this on the non secured builder is wrong.
         // AFAICS this is only relevant when the after node state has been moved here
-        builder.setNode(name, after);
+        builder.setChildNode(name, after);
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java Wed Apr 24 10:37:51 2013
@@ -212,7 +212,7 @@ public class TreeImpl implements Tree {
             else {
                 // make this builder disconnected from its new parent
                 nodeBuilder = parent.nodeBuilder.child(name);
-                parent.nodeBuilder.removeNode(name);
+                parent.nodeBuilder.removeChildNode(name);
             }
         }
         return nodeBuilder.isConnected();
@@ -305,7 +305,7 @@ public class TreeImpl implements Tree {
 
         if (!isRoot() && parent.hasChild(name)) {
             NodeBuilder parentBuilder = parent.nodeBuilder;
-            parentBuilder.removeNode(name);
+            parentBuilder.removeChildNode(name);
             if (parent.hasOrderableChildren()) {
                 parentBuilder.setProperty(
                         MemoryPropertyBuilder.copy(Type.STRING, parent.internalGetProperty(OAK_CHILD_ORDER))

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java Wed Apr 24 10:37:51 2013
@@ -16,13 +16,6 @@
  */
 package org.apache.jackrabbit.oak.plugins.commit;
 
-import java.util.List;
-
-import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.spi.commit.ConflictHandler;
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
-
 import static com.google.common.collect.Lists.newArrayList;
 import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
 import static org.apache.jackrabbit.oak.api.Type.NAMES;
@@ -34,6 +27,13 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.MIX_REP_MERGE_CONFLICT;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.REP_OURS;
 
+import java.util.List;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.spi.commit.ConflictHandler;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
 /**
  * This {@link ConflictHandler} implementation resolves conflicts to
  * {@link Resolution#THEIRS} and in addition marks nodes where a conflict
@@ -91,14 +91,14 @@ public class AnnotatingConflictHandler i
     @Override
     public Resolution addExistingNode(NodeBuilder parent, String name, NodeState ours, NodeState theirs) {
         NodeBuilder marker = addConflictMarker(parent);
-        marker.child(ADD_EXISTING).setNode(name, ours);
+        marker.child(ADD_EXISTING).setChildNode(name, ours);
         return Resolution.THEIRS;
     }
 
     @Override
     public Resolution changeDeletedNode(NodeBuilder parent, String name, NodeState ours) {
         NodeBuilder marker = addConflictMarker(parent);
-        marker.child(CHANGE_DELETED).setNode(name, ours);
+        marker.child(CHANGE_DELETED).setChildNode(name, ours);
         return Resolution.THEIRS;
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/MergingNodeStateDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/MergingNodeStateDiff.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/MergingNodeStateDiff.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/MergingNodeStateDiff.java Wed Apr 24 10:37:51 2013
@@ -81,7 +81,7 @@ public final class MergingNodeStateDiff 
                 resolveConflict(conflict.getName(), conflict.getNodeState());
             }
 
-            target.removeNode(CONFLICT);
+            target.removeChildNode(CONFLICT);
         }
     }
 
@@ -148,7 +148,7 @@ public final class MergingNodeStateDiff 
                 addChild(target, name, ours);
             }
         }
-        conflictMarker.removeNode(name);
+        conflictMarker.removeChildNode(name);
     }
 
     private NodeBuilder getConflictMarker(String conflictName) {
@@ -231,7 +231,7 @@ public final class MergingNodeStateDiff 
     );
 
     private static void addChild(NodeBuilder target, String name, NodeState state) {
-        target.setNode(name, state);
+        target.setChildNode(name, state);
         PropertyState childOrder = target.getProperty(TreeImpl.OAK_CHILD_ORDER);
         if (childOrder != null) {
             PropertyBuilder<String> builder = MemoryPropertyBuilder.copy(Type.STRING, childOrder);
@@ -241,7 +241,7 @@ public final class MergingNodeStateDiff 
     }
 
     private static void removeChild(NodeBuilder target, String name) {
-        target.removeNode(name);
+        target.removeChildNode(name);
         PropertyState childOrder = target.getProperty(TreeImpl.OAK_CHILD_ORDER);
         if (childOrder != null) {
             PropertyBuilder<String> builder = MemoryPropertyBuilder.copy(Type.STRING, childOrder);

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/strategy/ContentMirrorStoreStrategy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/strategy/ContentMirrorStoreStrategy.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/strategy/ContentMirrorStoreStrategy.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/strategy/ContentMirrorStoreStrategy.java Wed Apr 24 10:37:51 2013
@@ -96,7 +96,7 @@ public class ContentMirrorStoreStrategy 
                     NodeBuilder childEntry = indexEntry.child(name);
                     childEntry.removeProperty("match");
                     if (childEntry.getChildNodeCount() == 0) {
-                        indexEntry.removeNode(name);
+                        indexEntry.removeChildNode(name);
                     }
                 }
             }
@@ -114,7 +114,7 @@ public class ContentMirrorStoreStrategy 
         pruneNode(child);
         if (child.getChildNodeCount() == 0
                 && !child.hasProperty("match")) {
-            index.removeNode(key);
+            index.removeChildNode(key);
         }
     }
 
@@ -126,7 +126,7 @@ public class ContentMirrorStoreStrategy 
             NodeBuilder segment = parent.child(name);
             if (segment.getChildNodeCount() == 0
                     && !segment.hasProperty("match")) {
-                parent.removeNode(name);
+                parent.removeChildNode(name);
             }
         }
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java Wed Apr 24 10:37:51 2013
@@ -18,30 +18,18 @@ package org.apache.jackrabbit.oak.plugin
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Maps.newHashMap;
 import static java.util.Collections.emptyList;
 import static org.apache.jackrabbit.oak.api.Type.BOOLEAN;
 import static org.apache.jackrabbit.oak.api.Type.NAME;
 import static org.apache.jackrabbit.oak.api.Type.NAMES;
 import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
-import static org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState.with;
-import static org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState.withNodes;
-import static org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState.withProperties;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
 
-import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.spi.state.AbstractNodeState;
-import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
 
 /**
  * In-memory node state builder.
@@ -92,25 +80,21 @@ public class MemoryNodeBuilder implement
      */
     private final MemoryNodeBuilder root;
 
-    /**
-     * Internal revision counter that is incremented in the root builder
-     * whenever anything changes in the tree below. Each builder instance
-     * has its own copy of the revision counter, for quickly checking whether
-     * any state changes are needed.
-     */
-    private long revision;
+    private long baseRevision;
 
     /**
      * The base state of this builder, possibly non-existent if this builder
      * represents a new node that didn't yet exist in the base content tree.
      */
-    private NodeState baseState;
+    private NodeState base;
+
+    private long headRevision;
 
     /**
      * The shared mutable state of connected builder instances, or
      * {@code null} until this builder has been connected.
      */
-    private MutableNodeState writeState;
+    private MutableNodeState head;
 
     /**
      * Creates a new in-memory node state builder.
@@ -118,15 +102,10 @@ public class MemoryNodeBuilder implement
      * @param parent parent node state builder
      * @param name name of this node
      */
-    protected MemoryNodeBuilder(MemoryNodeBuilder parent, String name) {
-        this.parent = checkNotNull(parent);
-        this.name = checkNotNull(name);
-
+    private MemoryNodeBuilder(MemoryNodeBuilder parent, String name) {
+        this.parent = parent;
+        this.name = name;
         this.root = parent.root;
-        this.revision = -1;
-
-        this.baseState = parent.baseState.getChildNode(name);
-        this.writeState = null;
     }
 
     /**
@@ -137,141 +116,57 @@ public class MemoryNodeBuilder implement
     public MemoryNodeBuilder(@Nonnull NodeState base) {
         this.parent = null;
         this.name = null;
-
         this.root = this;
-        this.revision = 0;
 
-        this.baseState = checkNotNull(base);
-        this.writeState = new MutableNodeState(baseState);
-    }
+        this.baseRevision = 1;
+        this.base = checkNotNull(base);
 
-    private boolean classInvariants() {
-        boolean rootHasNoParent = isRoot() == (parent == null);
-        boolean rootHasWriteState = root.writeState != null;
-        return rootHasNoParent && rootHasWriteState;
+        this.headRevision = 1;
+        this.head = new MutableNodeState(this.base);
     }
 
     private boolean isRoot() {
         return this == root;
     }
 
-    /**
-     * Return the base state of the named child. Assumes {@code read()} needs not be called.
-     * @param name  name of the child
-     * @return  base state of the child
-     */
-    private NodeState getBaseState(String name) {
-        return baseState.getChildNode(name);
-    }
-
-    /**
-     * Determine whether the base state has a child of the given name.
-     * Assumes {@code read()} needs not be called.
-     * @param name  name of the child
-     * @return  {@code true} iff the base state has a child of the given name.
-     */
-    private boolean hasBaseState(String name) {
-        return baseState.hasChildNode(name);
-    }
-
-    /**
-     * Return the write state of the named child. Assumes {@code read()}, {@code write()} needs not be called.
-     * @param name  name of the child
-     * @return  base state of the child
-     */
-    private MutableNodeState getWriteState(String name) {
-        if (writeState != null) {
-            return writeState.nodes.get(name);
-        }
-        else {
-            return null;
-        }
-    }
-
-    /**
-     * Determine whether this child exists at its direct parent.
-     * @return {@code true} iff this child exists at its direct parent.
-     */
-    @Override // TODO: Check that the implementation matches NodeBuilder.exists()
-    public boolean exists() {
-        if (isRoot()) {
-            return true;
-        } else if (parent.writeState == null) {
-            return parent.baseState.hasChildNode(name);
-        } else {
-            return parent.writeState.hasChildNode(name);
+    private void checkConnected() {
+        if (!isConnected()) {
+            throw new IllegalStateException("This builder is not connected");
         }
     }
 
-    /**
-     * Update the state of this builder for reading.
-     * @return  {@code true} is this reader is connected, {@code false} otherwise.
-     */
-    private boolean updateReadState() {
-        if (revision != root.revision) {
-            assert(!isRoot()); // root never gets here since revision == root.revision
-
-            if (parent.updateReadState() && exists()) {
-                // The builder could have been reset, need to re-get base state
-                baseState = parent.getBaseState(name);
-
-                // ... same for the write state
-                writeState = parent.getWriteState(name);
-
-                revision = root.revision;
-                return true;
-            }
-
-            return false;
+    @Nonnull
+    private NodeState base() {
+        if (root.baseRevision != baseRevision) {
+            base = parent.base().getChildNode(name);
+            baseRevision = root.baseRevision;
         }
-        return writeState != null || baseState.exists();
+        return base;
     }
 
     @Nonnull
-    private NodeState read() {
-        checkState(updateReadState(), "This node has been removed or is disconnected");
-        assert classInvariants();
-        return writeState != null ? writeState : baseState;
+    private MutableNodeState read() {
+        if (headRevision != root.headRevision) {
+            assert !isRoot() : "root should have headRevision == root.headRevision";
+            head = parent.read().getChildNode(name, false);
+            headRevision = root.headRevision;
+        }
+        return head;
     }
 
     @Nonnull
     private MutableNodeState write() {
-        return write(root.revision + 1, false);
+        return write(root.headRevision + 1);
     }
 
     @Nonnull
-    private MutableNodeState write(long newRevision, boolean reconnect) {
-        // make sure that all revision numbers up to the root gets updated
-        if (!isRoot()) {
-            parent.write(newRevision, reconnect);
-            checkState(reconnect || exists(), "This node has been removed");
-        }
-
-        if (writeState == null || revision != root.revision) {
-            assert(!isRoot()); // root never gets here since revision == root.revision
-
-            // The builder could have been reset, need to re-get base state
-            baseState = parent.getBaseState(name);
-
-            writeState = parent.getWriteState(name);
-            if (writeState == null) {
-                if (exists()) {
-                    NodeState writeBase =
-                            parent.writeState.base.getChildNode(name);
-                    writeState = new MutableNodeState(writeBase);
-                }
-                else {
-                    writeState = new MutableNodeState(null);
-                }
-                assert parent.writeState != null; // guaranteed by called parent.write()
-                parent.writeState.nodes.put(name, writeState);
-            }
+    private MutableNodeState write(long newRevision) {
+        if (headRevision != newRevision && !isRoot()) {
+            head = parent.write(newRevision).getChildNode(name, true);
+            headRevision = newRevision;
         }
-
-        revision = newRevision;
-        assert classInvariants();
-        assert writeState != null;
-        return writeState;
+        root.headRevision = newRevision;
+        return head;
     }
 
     /**
@@ -298,136 +193,127 @@ public class MemoryNodeBuilder implement
     //--------------------------------------------------------< NodeBuilder >---
 
     @Override
-    public boolean isNew() {
-        return !isRoot() && parent.isNew(name);
+    public NodeState getNodeState() {
+        checkConnected();
+        return read().snapshot();
     }
 
-    private boolean isNew(String name) {
-        read();
-        return !hasBaseState(name) && hasChildNode(name);
+    @Override
+    public NodeState getBaseState() {
+        return base();
     }
 
     @Override
-    public boolean isConnected() {
-        return updateReadState();
+    public boolean exists() {
+        checkConnected();
+        return read().exists();
     }
 
     @Override
-    public boolean isModified() {
-        read();
-        if (writeState == null) {
-            return false;
-        }
-        else {
-            for (Entry<String, MutableNodeState> n : writeState.nodes.entrySet()) {
-                if (n.getValue() == null) {
-                    return true;
-                }
-                if (!(hasBaseState(n.getKey()))) {
-                    return true;
-                }
-            }
-            for (Entry<String, PropertyState> p : writeState.properties.entrySet()) {
-                PropertyState pState = p.getValue();
-                if (pState == null) {
-                    return true;
-                }
-                if (!baseState.exists()
-                        || !pState.equals(baseState.getProperty(p.getKey()))) {
-                    return true;
-                }
-            }
-            return false;
-        }
+    public boolean isNew() {
+        checkConnected();
+        return !isRoot() && !parent.base().hasChildNode(name) && parent.hasChildNode(name);
     }
 
     @Override
-    public NodeState getNodeState() {
-        read();
-        if (writeState != null) {
-            return writeState.snapshot();
-        } else {
-            assert baseState.exists();
-            return baseState;
-        }
+    public boolean isConnected() {
+        return isRoot() || parent.read().isConnected(name);
     }
 
     @Override
-    public NodeState getBaseState() {
-        read();
-        return baseState;
+    public boolean isModified() {
+        checkConnected();
+        return read().isModified(base());
     }
 
     @Override
     public void reset(NodeState newBase) {
         checkState(isRoot(), "Cannot reset a non-root builder");
-        baseState = checkNotNull(newBase);
-        writeState = new MutableNodeState(baseState);
-        revision++;
+        base = checkNotNull(newBase);
+        root.baseRevision++;
+        root.headRevision++;
+        head = new MutableNodeState(base);
     }
 
     @Override
     public long getChildNodeCount() {
+        checkConnected();
         return read().getChildNodeCount();
     }
 
     @Override
-    public boolean hasChildNode(String name) {
-        return read().hasChildNode(name);
+    public Iterable<String> getChildNodeNames() {
+        checkConnected();
+        return read().getChildNodeNames();
     }
 
     @Override
-    public Iterable<String> getChildNodeNames() {
-        return read().getChildNodeNames();
+    public boolean hasChildNode(String name) {
+        checkConnected();
+        return read().hasChildNode(checkNotNull(name));
     }
 
-    @Override @Nonnull
-    public NodeBuilder setNode(String name, NodeState state) {
-        write();
-
-        MutableNodeState childState = getWriteState(name);
-        if (childState == null) {
-            writeState.nodes.remove(name);
-            childState = createChildBuilder(name).write(root.revision + 1, true);
+    @Override
+    public NodeBuilder child(String name) {
+        if (hasChildNode(name)) {
+            return getChildNode(name);
+        }
+        else {
+            return setChildNode(name);
         }
-        childState.reset(state);
-
-        updated();
-        return this;
     }
 
-    @Override @Nonnull
-    public NodeBuilder removeNode(String name) {
-        write();
+    @Override
+    public NodeBuilder getChildNode(String name) {
+        checkConnected();
+        return createChildBuilder(checkNotNull(name));
+    }
 
-        if (writeState.base.getChildNode(name).exists()) {
-            writeState.nodes.put(name, null);
-        } else {
-            writeState.nodes.remove(name);
-        }
+    @Override
+    public NodeBuilder setChildNode(String name) {
+        return setChildNode(checkNotNull(name), EMPTY_NODE);
+    }
 
+    @Override
+    public NodeBuilder setChildNode(String name, NodeState state) {
+        checkConnected();
+        write().setChildNode(checkNotNull(name), checkNotNull(state));
+        MemoryNodeBuilder builder = createChildBuilder(name);
         updated();
+        return builder;
+    }
+
+    @Override
+    public NodeBuilder removeChildNode(String name) {
+        checkConnected();
+        if (write().removeChildNode(checkNotNull(name))) {
+            updated();
+        }
         return this;
     }
 
     @Override
     public long getPropertyCount() {
+        checkConnected();
         return read().getPropertyCount();
     }
 
     @Override
     public Iterable<? extends PropertyState> getProperties() {
+        checkConnected();
         return read().getProperties();
     }
 
     @Override
     public boolean hasProperty(String name) {
-        return read().hasProperty(name);
+        checkConnected();
+        return read().hasProperty(checkNotNull(name));
     }
 
     @Override
     public PropertyState getProperty(String name) {
-        return read().getProperty(name);
+        checkConnected();
+        return read().getProperty(checkNotNull(name));
     }
 
     @Override
@@ -438,7 +324,7 @@ public class MemoryNodeBuilder implement
                 && property.getValue(BOOLEAN);
     }
 
-    @Override @CheckForNull
+    @Override
     public String getName(@Nonnull String name) {
         PropertyState property = getProperty(name);
         if (property != null && property.getType() == NAME) {
@@ -448,7 +334,7 @@ public class MemoryNodeBuilder implement
         }
     }
 
-    @Override @Nonnull
+    @Override
     public Iterable<String> getNames(@Nonnull String name) {
         PropertyState property = getProperty(name);
         if (property != null && property.getType() == NAMES) {
@@ -458,24 +344,10 @@ public class MemoryNodeBuilder implement
         }
     }
 
-    @Override @Nonnull
-    public NodeBuilder removeProperty(String name) {
-        write();
-
-        if (writeState.base.hasProperty(name)) {
-            writeState.properties.put(name, null);
-        } else {
-            writeState.properties.remove(name);
-        }
-
-        updated();
-        return this;
-    }
-
     @Override
     public NodeBuilder setProperty(PropertyState property) {
-        write();
-        writeState.properties.put(property.getName(), property);
+        checkConnected();
+        write().setProperty(checkNotNull(property));
         updated();
         return this;
     }
@@ -493,274 +365,12 @@ public class MemoryNodeBuilder implement
     }
 
     @Override
-    public NodeBuilder child(String name) {
-        read();
-        MemoryNodeBuilder builder = createChildBuilder(name);
-
-        boolean modified = writeState != null && (writeState.base != baseState || writeState.nodes.containsKey(name));
-        if (!hasBaseState(name) || modified) {
-            builder.write(root.revision + 1, true);
-        }
-        return builder;
-    }
-
-    @Override @Nonnull
-    public NodeBuilder getChild(@Nonnull String name) {
-        throw new UnsupportedOperationException(); // TODO
-    }
-
-    @Override @Nonnull
-    public NodeBuilder addChild(@Nonnull String name) {
-        // TODO: better implementation?
-        setNode(name, EMPTY_NODE);
-        return child(name);
-    }
-
-    /**
-     * The <em>mutable</em> state being built. Instances of this class
-     * are never passed beyond the containing {@code MemoryNodeBuilder},
-     * so it's not a problem that we intentionally break the immutability
-     * assumption of the {@link NodeState} interface.
-     */
-    private static class MutableNodeState extends AbstractNodeState {
-
-        /**
-         * The immutable base state.
-         */
-        private NodeState base;
-
-        /**
-         * Set of added, modified or removed ({@code null} value)
-         * property states.
-         */
-        private final Map<String, PropertyState> properties = newHashMap();
-
-        /**
-         * Set of added, modified or removed ({@code null} value)
-         * child nodes.
-         */
-        private final Map<String, MutableNodeState> nodes = newHashMap();
-
-        public MutableNodeState(NodeState base) {
-            if (base instanceof ModifiedNodeState) {
-                ModifiedNodeState modified = (ModifiedNodeState) base;
-                this.base = modified.getBaseState();
-                modified.compareAgainstBaseState(new NodeStateDiff() {
-                    @Override
-                    public void propertyAdded(PropertyState after) {
-                        properties.put(after.getName(), after);
-                    }
-                    @Override
-                    public void propertyChanged(
-                            PropertyState before, PropertyState after) {
-                        properties.put(after.getName(), after);
-                    }
-                    @Override
-                    public void propertyDeleted(PropertyState before) {
-                        properties.put(before.getName(), null);
-                    }
-                    @Override
-                    public void childNodeAdded(String name, NodeState after) {
-                        nodes.put(name, new MutableNodeState(after));
-                    }
-                    @Override
-                    public void childNodeChanged(
-                            String name, NodeState before, NodeState after) {
-                        nodes.put(name, new MutableNodeState(after));
-                    }
-                    @Override
-                    public void childNodeDeleted(String name, NodeState before) {
-                        nodes.put(name, null);
-                    }
-                });
-            } else if (base != null) {
-                this.base = base;
-            } else {
-                this.base = EMPTY_NODE;
-            }
-        }
-
-        public NodeState snapshot() {
-            Map<String, NodeState> nodes = newHashMap();
-            for (Map.Entry<String, MutableNodeState> entry : this.nodes.entrySet()) {
-                String name = entry.getKey();
-                MutableNodeState node = entry.getValue();
-                NodeState before = base.getChildNode(name);
-                if (node == null) {
-                    if (before.exists()) {
-                        nodes.put(name, null);
-                    }
-                } else {
-                    NodeState after = node.snapshot();
-                    if (after != before) {
-                        nodes.put(name, after);
-                    }
-                }
-            }
-            return with(base, newHashMap(this.properties), nodes);
-        }
-
-        void reset(NodeState newBase) {
-            if (newBase instanceof ModifiedNodeState) {
-                ModifiedNodeState modified = (ModifiedNodeState) newBase;
-                base = modified.getBaseState();
-                properties.clear();
-
-                Iterator<Map.Entry<String, MutableNodeState>> iterator =
-                        nodes.entrySet().iterator();
-                while (iterator.hasNext()) {
-                    Map.Entry<String, MutableNodeState> entry = iterator.next();
-                    MutableNodeState cstate = entry.getValue();
-                    NodeState cbase = newBase.getChildNode(entry.getKey());
-                    if (!cbase.exists() || cstate == null) {
-                        iterator.remove();
-                    } else {
-                        cstate.reset(cbase);
-                    }
-                }
-
-                modified.compareAgainstBaseState(new NodeStateDiff() {
-                    @Override
-                    public void propertyAdded(PropertyState after) {
-                        properties.put(after.getName(), after);
-                    }
-                    @Override
-                    public void propertyChanged(
-                            PropertyState before, PropertyState after) {
-                        properties.put(after.getName(), after);
-                    }
-                    @Override
-                    public void propertyDeleted(PropertyState before) {
-                        properties.put(before.getName(), null);
-                    }
-                    @Override
-                    public void childNodeAdded(String name, NodeState after) {
-                        MutableNodeState cstate = nodes.get(name);
-                        if (cstate != null) {
-                            cstate.reset(after);
-                        } else {
-                            nodes.put(name, new MutableNodeState(after));
-                        }
-                    }
-                    @Override
-                    public void childNodeChanged(
-                            String name, NodeState before, NodeState after) {
-                        MutableNodeState cstate = nodes.get(name);
-                        if (cstate != null) {
-                            cstate.reset(after);
-                        } else {
-                            nodes.put(name, new MutableNodeState(after));
-                        }
-                    }
-                    @Override
-                    public void childNodeDeleted(String name, NodeState before) {
-                        nodes.put(name, null);
-                    }
-                });
-            } else {
-                base = newBase;
-                properties.clear();
-
-                Iterator<Map.Entry<String, MutableNodeState>> iterator =
-                        nodes.entrySet().iterator();
-                while (iterator.hasNext()) {
-                    Map.Entry<String, MutableNodeState> entry = iterator.next();
-                    MutableNodeState cstate = entry.getValue();
-                    NodeState cbase = newBase.getChildNode(entry.getKey());
-                    if (!cbase.exists() || cstate == null) {
-                        iterator.remove();
-                    } else {
-                        cstate.reset(cbase);
-                    }
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder builder = new StringBuilder();
-            builder.append(base).append(" + {");
-            String separator = " ";
-            for (PropertyState property : properties.values()) {
-                builder.append(separator);
-                separator = ", ";
-                builder.append(property);
-            }
-            for (Entry<String, MutableNodeState> entry : nodes.entrySet()) {
-                builder.append(separator);
-                separator = ", ";
-                builder.append(entry.getKey()).append(" : ").append(entry.getValue());
-            }
-            builder.append(" }");
-            return builder.toString();
-        }
-
-        //-----------------------------------------------------< NodeState >--
-
-        @Override
-        public boolean exists() {
-            return true;
-        }
-
-        @Override
-        public long getPropertyCount() {
-            return withProperties(base, properties).getPropertyCount();
-        }
-
-        @Override
-        public boolean hasProperty(String name) {
-            return withProperties(base, properties).hasProperty(name);
-        }
-
-        @Override
-        public PropertyState getProperty(String name) {
-            return withProperties(base, properties).getProperty(name);
-        }
-
-        @Override @Nonnull
-        public Iterable<? extends PropertyState> getProperties() {
-            Map<String, PropertyState> copy = newHashMap(properties);
-            return withProperties(base, copy).getProperties();
-        }
-
-        @Override
-        public long getChildNodeCount() {
-            return withNodes(base, nodes).getChildNodeCount();
-        }
-
-        @Override
-        public boolean hasChildNode(String name) {
-            checkNotNull(name);
-            // checkArgument(!name.isEmpty()); TODO: should be caught earlier
-            return withNodes(base, nodes).hasChildNode(name);
-        }
-
-        @Override
-        public NodeState getChildNode(String name) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override @Nonnull
-        public Iterable<String> getChildNodeNames() {
-            Map<String, MutableNodeState> copy = newHashMap(nodes);
-            return withNodes(base, copy).getChildNodeNames();
-        }
-
-        @Override @Nonnull
-        public Iterable<? extends ChildNodeEntry> getChildNodeEntries() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void compareAgainstBaseState(NodeState base, NodeStateDiff diff) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override @Nonnull
-        public NodeBuilder builder() {
-            throw new UnsupportedOperationException();
+    public NodeBuilder removeProperty(String name) {
+        checkConnected();
+        if (write().removeProperty(checkNotNull(name))) {
+            updated();
         }
-
+        return this;
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/ModifiedNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/ModifiedNodeState.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/ModifiedNodeState.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/ModifiedNodeState.java Wed Apr 24 10:37:51 2013
@@ -47,6 +47,7 @@ import com.google.common.collect.Maps;
  * Immutable snapshot of a mutable node state.
  */
 public class ModifiedNodeState extends AbstractNodeState {
+    // FIXME implement correct contract wrt. existence and iterability
 
     static NodeState withProperties(
             NodeState base, Map<String, ? extends PropertyState> properties) {
@@ -135,7 +136,7 @@ public class ModifiedNodeState extends A
 
     @Override
     public boolean exists() {
-        return true;
+        return base.exists();
     }
 
     @Override
@@ -216,7 +217,7 @@ public class ModifiedNodeState extends A
         // checkArgument(!checkNotNull(name).isEmpty()); // TODO: should be caught earlier
         NodeState child = nodes.get(name);
         if (child != null) {
-            return true;
+            return child.exists();
         } else if (nodes.containsKey(name)) {
             return false;
         } else {

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MutableNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MutableNodeState.java?rev=1471355&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MutableNodeState.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MutableNodeState.java Wed Apr 24 10:37:51 2013
@@ -0,0 +1,391 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.jackrabbit.oak.plugins.memory;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Maps.newHashMap;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.MISSING_NODE;
+import static org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState.with;
+import static org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState.withNodes;
+import static org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState.withProperties;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.spi.state.AbstractNodeState;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+
+/**
+ * The <em>mutable</em> state being built. Instances of this class
+ * are never passed beyond the containing {@code MemoryNodeBuilder},
+ * so it's not a problem that we intentionally break the immutability
+ * assumption of the {@link org.apache.jackrabbit.oak.spi.state.NodeState} interface.
+ */
+class MutableNodeState extends AbstractNodeState {
+
+    /**
+     * The immutable base state.
+     */
+    private NodeState base;
+
+    /**
+     * Set of added, modified or removed ({@code null} value)
+     * property states.
+     */
+    private final Map<String, PropertyState> properties = newHashMap();
+
+    /**
+     * Set of added, modified or removed ({@code null} value)
+     * child nodes.
+     */
+    private final Map<String, MutableNodeState> nodes = newHashMap();
+
+    public MutableNodeState(boolean exists) {
+        this.base = exists ? EMPTY_NODE : MISSING_NODE;
+    }
+
+    public MutableNodeState(@Nonnull NodeState base) {
+        if (checkNotNull(base) instanceof ModifiedNodeState) {
+            ModifiedNodeState modified = (ModifiedNodeState) base;
+            this.base = modified.getBaseState();
+            modified.compareAgainstBaseState(new NodeStateDiff() {
+                @Override
+                public void propertyAdded(PropertyState after) {
+                    properties.put(after.getName(), after);
+                }
+                @Override
+                public void propertyChanged(
+                        PropertyState before, PropertyState after) {
+                    properties.put(after.getName(), after);
+                }
+                @Override
+                public void propertyDeleted(PropertyState before) {
+                    properties.put(before.getName(), null);
+                }
+                @Override
+                public void childNodeAdded(String name, NodeState after) {
+                    nodes.put(name, new MutableNodeState(after));
+                }
+                @Override
+                public void childNodeChanged(
+                        String name, NodeState before, NodeState after) {
+                    nodes.put(name, new MutableNodeState(after));
+                }
+                @Override
+                public void childNodeDeleted(String name, NodeState before) {
+                    nodes.put(name, null);
+                }
+            });
+        } else {
+            this.base = base;
+        }
+    }
+
+    public NodeState snapshot() {
+        assert base != null;
+
+        Map<String, NodeState> nodes = newHashMap();
+        for (Map.Entry<String, MutableNodeState> entry : this.nodes.entrySet()) {
+            String name = entry.getKey();
+            MutableNodeState node = entry.getValue();
+            NodeState before = base.getChildNode(name);
+            if (node == null) {
+                if (before.exists()) {
+                    nodes.put(name, null);
+                }
+            } else {
+                NodeState after = node.snapshot();
+                if (after != before) {
+                    nodes.put(name, after);
+                }
+            }
+        }
+        return with(base, newHashMap(this.properties), nodes);
+    }
+
+    private void reset(NodeState newBase) {
+        assert base != null;
+
+        if (newBase instanceof ModifiedNodeState) {
+            ModifiedNodeState modified = (ModifiedNodeState) newBase;
+            base = modified.getBaseState();
+            properties.clear();
+
+            Iterator<Entry<String, MutableNodeState>> iterator =
+                    nodes.entrySet().iterator();
+            while (iterator.hasNext()) {
+                Entry<String, MutableNodeState> entry = iterator.next();
+                MutableNodeState cstate = entry.getValue();
+                NodeState cbase = newBase.getChildNode(entry.getKey());
+                if (!cbase.exists() || cstate == null) {
+                    iterator.remove();
+                } else {
+                    cstate.reset(cbase);
+                }
+            }
+
+            modified.compareAgainstBaseState(new NodeStateDiff() {
+                @Override
+                public void propertyAdded(PropertyState after) {
+                    properties.put(after.getName(), after);
+                }
+                @Override
+                public void propertyChanged(
+                        PropertyState before, PropertyState after) {
+                    properties.put(after.getName(), after);
+                }
+                @Override
+                public void propertyDeleted(PropertyState before) {
+                    properties.put(before.getName(), null);
+                }
+                @Override
+                public void childNodeAdded(String name, NodeState after) {
+                    MutableNodeState cstate = nodes.get(name);
+                    if (cstate != null) {
+                        cstate.reset(after);
+                    } else {
+                        nodes.put(name, new MutableNodeState(after));
+                    }
+                }
+                @Override
+                public void childNodeChanged(
+                        String name, NodeState before, NodeState after) {
+                    MutableNodeState cstate = nodes.get(name);
+                    if (cstate != null) {
+                        cstate.reset(after);
+                    } else {
+                        nodes.put(name, new MutableNodeState(after));
+                    }
+                }
+                @Override
+                public void childNodeDeleted(String name, NodeState before) {
+                    nodes.put(name, null);
+                }
+            });
+        } else {
+            base = newBase;
+            properties.clear();
+
+            Iterator<Entry<String, MutableNodeState>> iterator =
+                    nodes.entrySet().iterator();
+            while (iterator.hasNext()) {
+                Entry<String, MutableNodeState> entry = iterator.next();
+                MutableNodeState cstate = entry.getValue();
+                NodeState cbase = newBase.getChildNode(entry.getKey());
+                if (!cbase.exists() || cstate == null) {
+                    iterator.remove();
+                } else {
+                    cstate.reset(cbase);
+                }
+            }
+        }
+    }
+
+    public boolean isConnected(String name) {
+        assert base != null;
+
+        return nodes.get(name) != null ||
+                !nodes.containsKey(name) && base.getChildNode(name).exists();
+    }
+
+    public MutableNodeState getChildNode(String name, boolean connect) {
+        assert base != null;
+
+        MutableNodeState child = nodes.get(name);
+        if (child != null) {
+            return child;
+        }
+
+        if (nodes.containsKey(name)) {
+            // deleted
+            child = new MutableNodeState(connect);
+        } else {
+            child = new MutableNodeState(base.getChildNode(name));
+        }
+
+        if (connect) {
+            nodes.put(name, child);
+        }
+        return child;
+    }
+
+    @Nonnull
+    public MutableNodeState setChildNode(String name, NodeState state) {
+        // FIXME better implementation, which doesn't set the base state twice
+        MutableNodeState child = getChildNode(name, true);
+        child.reset(state);
+        return child;
+    }
+
+    public boolean isModified(NodeState before) {
+        if (nodes.isEmpty() && properties.isEmpty()) {
+            return false;
+        }
+
+        for (Entry<String, MutableNodeState> n : nodes.entrySet()) {
+            if (n.getValue() == null) {
+                return true;
+            }
+            if (!(before.hasChildNode(n.getKey()))) {
+                return true;
+            }
+        }
+        for (Entry<String, PropertyState> p : properties.entrySet()) {
+            PropertyState pState = p.getValue();
+            if (pState == null) {
+                return true;
+            }
+            if (!before.exists() || !pState.equals(before.getProperty(p.getKey()))) {
+                return true;
+            }
+        }
+        return false;
+
+    }
+
+    public boolean removeChildNode(String name) {
+        assert base != null;
+
+        if (base.getChildNode(name).exists()) {
+            nodes.put(name, null);
+            return true;
+        } else {
+            return nodes.remove(name) != null;
+        }
+    }
+
+    public boolean removeProperty(String name) {
+        assert base != null;
+
+        if (base.hasProperty(name)) {
+            properties.put(name, null);
+            return true;
+        } else {
+            return properties.remove(name) != null;
+        }
+    }
+
+    public void setProperty(PropertyState property) {
+        properties.put(property.getName(), property);
+    }
+
+    @Override
+    public String toString() {
+        assert base != null;
+
+        StringBuilder builder = new StringBuilder();
+        builder.append(base).append(" + {");
+        String separator = " ";
+        for (PropertyState property : properties.values()) {
+            builder.append(separator);
+            separator = ", ";
+            builder.append(property);
+        }
+        for (Entry<String, MutableNodeState> entry : nodes.entrySet()) {
+            builder.append(separator);
+            separator = ", ";
+            builder.append(entry.getKey()).append(" : ").append(entry.getValue());
+        }
+        builder.append(" }");
+        return builder.toString();
+    }
+
+    //-----------------------------------------------------< NodeState >--
+
+    @Override
+    public boolean exists() {
+        assert base != null;
+        return base.exists();
+    }
+
+    @Override
+    public long getPropertyCount() {
+        assert base != null;
+        return withProperties(base, properties).getPropertyCount();
+    }
+
+    @Override
+    public boolean hasProperty(String name) {
+        assert base != null;
+        return withProperties(base, properties).hasProperty(name);
+    }
+
+    @Override
+    public PropertyState getProperty(String name) {
+        assert base != null;
+        return withProperties(base, properties).getProperty(name);
+    }
+
+    @Override @Nonnull
+    public Iterable<? extends PropertyState> getProperties() {
+        assert base != null;
+        Map<String, PropertyState> copy = newHashMap(properties);
+        return withProperties(base, copy).getProperties();
+    }
+
+    @Override
+    public long getChildNodeCount() {
+        assert base != null;
+        return withNodes(base, nodes).getChildNodeCount();
+    }
+
+    @Override
+    public boolean hasChildNode(String name) {
+        assert base != null;
+        checkNotNull(name);
+        // checkArgument(!name.isEmpty()); TODO: should be caught earlier
+        return withNodes(base, nodes).hasChildNode(name);
+    }
+
+    @Override
+    public MutableNodeState getChildNode(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override @Nonnull
+    public Iterable<String> getChildNodeNames() {
+        assert base != null;
+        Map<String, MutableNodeState> copy = newHashMap(nodes);
+        return withNodes(base, copy).getChildNodeNames();
+    }
+
+    @Override @Nonnull
+    public Iterable<? extends ChildNodeEntry> getChildNodeEntries() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void compareAgainstBaseState(NodeState base, NodeStateDiff diff) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override @Nonnull
+    public NodeBuilder builder() {
+        throw new UnsupportedOperationException();
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MutableNodeState.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MutableNodeState.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java Wed Apr 24 10:37:51 2013
@@ -187,7 +187,7 @@ class RegistrationEditor extends Default
         NodeState subtree = state.getChildNode(name);
         if (subtree.exists()) {
             if (!builder.hasChildNode(name)) {
-                builder.setNode(name, subtree);
+                builder.setChildNode(name, subtree);
             } else if (depth > 0) {
                 NodeBuilder subbuilder = builder.child(name);
                 for (String subname : subtree.getChildNodeNames()) {
@@ -225,10 +225,10 @@ class RegistrationEditor extends Default
         type.setProperty(OAK_MANDATORY_PROPERTIES, empty, NAMES);
         type.setProperty(OAK_MANDATORY_CHILD_NODES, empty, NAMES);
         type.setProperty(OAK_NAMED_SINGLE_VALUED_PROPERTIES, empty, NAMES);
-        type.removeNode(OAK_NAMED_PROPERTY_DEFINITIONS);
-        type.removeNode(OAK_RESIDUAL_PROPERTY_DEFINITIONS);
-        type.removeNode(OAK_NAMED_CHILD_NODE_DEFINITIONS);
-        type.removeNode(OAK_RESIDUAL_CHILD_NODE_DEFINITIONS);
+        type.removeChildNode(OAK_NAMED_PROPERTY_DEFINITIONS);
+        type.removeChildNode(OAK_RESIDUAL_PROPERTY_DEFINITIONS);
+        type.removeChildNode(OAK_NAMED_CHILD_NODE_DEFINITIONS);
+        type.removeChildNode(OAK_RESIDUAL_CHILD_NODE_DEFINITIONS);
 
         // + jcr:propertyDefinition (nt:propertyDefinition)
         //   = nt:propertyDefinition protected sns
@@ -306,7 +306,7 @@ class RegistrationEditor extends Default
             addNameToList(type, OAK_NAMED_SINGLE_VALUED_PROPERTIES, propertyName);
         }
 
-        definitions.setNode(key, definition);
+        definitions.setChildNode(key, definition);
     }
 
     private void validateAndCompileChildNodeDefinition(
@@ -343,7 +343,7 @@ class RegistrationEditor extends Default
                             "Constraint", 33,
                             "Unknown required primary type " + key);
                 } else if (!definitions.hasChildNode(key)) {
-                    definitions.setNode(key, definition);
+                    definitions.setChildNode(key, definition);
                 }
             }
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MergeDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MergeDiff.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MergeDiff.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/MergeDiff.java Wed Apr 24 10:37:51 2013
@@ -55,7 +55,7 @@ class MergeDiff implements NodeStateDiff
     @Override
     public void childNodeAdded(String name, NodeState after) {
         if (!builder.hasChildNode(name)) {
-            builder.setNode(name, after);
+            builder.setChildNode(name, after);
         }
     }
 
@@ -72,7 +72,7 @@ class MergeDiff implements NodeStateDiff
     public void childNodeDeleted(String name, NodeState before) {
         if (builder.hasChildNode(name)
                 && before.equals(builder.child(name).getNodeState())) {
-            builder.removeNode(name);
+            builder.removeChildNode(name);
         }
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/SegmentNodeStoreBranch.java Wed Apr 24 10:37:51 2013
@@ -162,8 +162,8 @@ class SegmentNodeStoreBranch extends Abs
         }
 
         NodeState sourceState = sourceBuilder.child(sourceName).getNodeState();
-        targetBuilder.setNode(targetName, sourceState);
-        sourceBuilder.removeNode(sourceName);
+        targetBuilder.setChildNode(targetName, sourceState);
+        sourceBuilder.removeChildNode(sourceName);
 
         setRoot(builder.getNodeState());
         return true;
@@ -202,7 +202,7 @@ class SegmentNodeStoreBranch extends Abs
         }
 
         NodeState sourceState = sourceBuilder.child(sourceName).getNodeState();
-        targetBuilder.setNode(targetName, sourceState);
+        targetBuilder.setChildNode(targetName, sourceState);
 
         setRoot(builder.getNodeState());
         return true;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java Wed Apr 24 10:37:51 2013
@@ -230,7 +230,7 @@ public class PermissionHook implements P
             PermissionEntry entry = createPermissionEntry(name, ace, parentBefore);
             NodeBuilder principalRoot = getPrincipalRoot(entry.principalName);
             if (principalRoot != null) {
-                principalRoot.removeNode(entry.nodeName);
+                principalRoot.removeChildNode(entry.nodeName);
             }
         }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractRebaseDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractRebaseDiff.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractRebaseDiff.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractRebaseDiff.java Wed Apr 24 10:37:51 2013
@@ -204,7 +204,7 @@ public abstract class AbstractRebaseDiff
             NodeState other = builder.child(name).getNodeState();
             addExistingNode(builder, name, other, after);
         } else {
-            builder.setNode(name, after);
+            builder.setChildNode(name, after);
         }
     }
 
@@ -223,7 +223,7 @@ public abstract class AbstractRebaseDiff
         if (!builder.hasChildNode(name)) {
             deleteDeletedNode(builder, name, before);
         } else if (before.equals(builder.child(name).getNodeState())) {
-            builder.removeNode(name);
+            builder.removeChildNode(name);
         } else {
             deleteChangedNode(builder, name, before);
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ConflictAnnotatingRebaseDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ConflictAnnotatingRebaseDiff.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ConflictAnnotatingRebaseDiff.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ConflictAnnotatingRebaseDiff.java Wed Apr 24 10:37:51 2013
@@ -73,22 +73,22 @@ public class ConflictAnnotatingRebaseDif
 
     @Override
     protected void addExistingNode(NodeBuilder builder, String name, NodeState before, NodeState after) {
-        conflictMarker(builder, ADD_EXISTING_NODE).setNode(name, after);
+        conflictMarker(builder, ADD_EXISTING_NODE).setChildNode(name, after);
     }
 
     @Override
     protected void changeDeletedNode(NodeBuilder builder, String name, NodeState after) {
-        conflictMarker(builder, CHANGE_DELETED_NODE).setNode(name, after);
+        conflictMarker(builder, CHANGE_DELETED_NODE).setChildNode(name, after);
     }
 
     @Override
     protected void deleteDeletedNode(NodeBuilder builder, String name, NodeState before) {
-        conflictMarker(builder, DELETE_DELETED_NODE).setNode(name, before);
+        conflictMarker(builder, DELETE_DELETED_NODE).setChildNode(name, before);
     }
 
     @Override
     protected void deleteChangedNode(NodeBuilder builder, String name, NodeState before) {
-        conflictMarker(builder, DELETE_CHANGED_NODE).setNode(name, before);
+        conflictMarker(builder, DELETE_CHANGED_NODE).setChildNode(name, before);
     }
 
     private static NodeBuilder conflictMarker(NodeBuilder builder, String name) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java Wed Apr 24 10:37:51 2013
@@ -98,6 +98,14 @@ public interface NodeBuilder {
     long getChildNodeCount();
 
     /**
+     * Returns the names of current child nodes.
+     *
+     * @return child node names
+     */
+    @Nonnull
+    Iterable<String> getChildNodeNames();
+
+    /**
      * Checks whether the named child node currently exists.
      *
      * @param name child node name
@@ -107,12 +115,52 @@ public interface NodeBuilder {
     boolean hasChildNode(@Nonnull String name);
 
     /**
-     * Returns the names of current child nodes.
+     * Returns a builder for constructing changes to the named child node.
+     * If the named child node does not already exist, a new empty child
+     * node is automatically created as the base state of the returned
+     * child builder. Otherwise the existing child node state is used
+     * as the base state of the returned builder.
+     * <p>
+     * All updates to the returned child builder will implicitly affect
+     * also this builder, as if a
+     * {@code setNode(name, childBuilder.getNodeState())} method call
+     * had been made after each update. Repeated calls to this method with
+     * the same name will return the same child builder instance until an
+     * explicit {@link #setChildNode(String, NodeState)} or
+     * {@link #removeChildNode(String)} call is made, at which point the link
+     * between this builder and a previously returned child builder for
+     * that child node name will get broken.
      *
-     * @return child node names
+     * @since Oak 0.6
+     * @param name name of the child node
+     * @return child builder
      */
     @Nonnull
-    Iterable<String> getChildNodeNames();
+    NodeBuilder child(@Nonnull String name);
+
+    /**
+     * Returns a builder for constructing changes to the named child node.
+     * If the named child node does not already exist, the returned builder
+     * will refer to a non-existent node and trying to modify it will cause
+     * {@link IllegalStateException}s to be thrown.
+     *
+     * @since Oak 0.7
+     * @param name name of the child node
+     * @return child builder, possibly non-existent
+     */
+    @Nonnull
+    NodeBuilder getChildNode(@Nonnull String name);
+
+    /**
+     * Adds the named child node and returns a builder for modifying it.
+     * Possible previous content in the named subtree is removed.
+     *
+     * @since Oak 0.7
+     * @param name name of the child node
+     * @return child builder
+     */
+    @Nonnull
+    NodeBuilder setChildNode(@Nonnull String name);
 
     /**
      * Adds or replaces a subtree.
@@ -122,7 +170,7 @@ public interface NodeBuilder {
      * @return this builder
      */
     @Nonnull
-    NodeBuilder setNode(String name, @Nonnull NodeState nodeState);
+    NodeBuilder setChildNode(String name, @Nonnull NodeState nodeState);
 
     /**
      * Remove a child node. This method has no effect if a
@@ -132,7 +180,7 @@ public interface NodeBuilder {
      * @return this builder
      */
     @Nonnull
-    NodeBuilder removeNode(String name);
+    NodeBuilder removeChildNode(String name);
 
     /**
      * Returns the current number of properties.
@@ -260,52 +308,4 @@ public interface NodeBuilder {
     @Nonnull
     NodeBuilder removeProperty(String name);
 
-    /**
-     * Returns a builder for constructing changes to the named child node.
-     * If the named child node does not already exist, a new empty child
-     * node is automatically created as the base state of the returned
-     * child builder. Otherwise the existing child node state is used
-     * as the base state of the returned builder.
-     * <p>
-     * All updates to the returned child builder will implicitly affect
-     * also this builder, as if a
-     * {@code setNode(name, childBuilder.getNodeState())} method call
-     * had been made after each update. Repeated calls to this method with
-     * the same name will return the same child builder instance until an
-     * explicit {@link #setNode(String, NodeState)} or
-     * {@link #removeNode(String)} call is made, at which point the link
-     * between this builder and a previously returned child builder for
-     * that child node name will get broken.
-     *
-     * @since Oak 0.6
-     * @param name name of the child node
-     * @return child builder
-     */
-    @Nonnull
-    NodeBuilder child(@Nonnull String name);
-
-    /**
-     * Returns a builder for constructing changes to the named child node.
-     * If the named child node does not already exist, the returned builder
-     * will refer to a non-existent node and trying to modify it will cause
-     * {@link IllegalStateException}s to be thrown.
-     *
-     * @since Oak 0.7
-     * @param name name of the child node
-     * @return child builder, possibly non-existent
-     */
-    @Nonnull
-    NodeBuilder getChild(@Nonnull String name);
-
-    /**
-     * Adds the named child node and returns a builder for modifying it.
-     * Possible previous content in the named subtree is removed.
-     *
-     * @since Oak 0.7
-     * @param name name of the child node
-     * @return child builder
-     */
-    @Nonnull
-    NodeBuilder addChild(@Nonnull String name);
-
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java Wed Apr 24 10:37:51 2013
@@ -89,12 +89,12 @@ public class ReadOnlyBuilder implements 
     }
 
     @Override @Nonnull
-    public NodeBuilder setNode(String name, NodeState nodeState) {
+    public NodeBuilder setChildNode(String name, NodeState nodeState) {
         throw unsupported();
     }
 
     @Override @Nonnull
-    public NodeBuilder removeNode(String name) {
+    public NodeBuilder removeChildNode(String name) {
         throw unsupported();
     }
 
@@ -164,12 +164,12 @@ public class ReadOnlyBuilder implements 
     }
 
     @Override @Nonnull
-    public NodeBuilder getChild(@Nonnull String name) {
+    public NodeBuilder getChildNode(@Nonnull String name) {
         return new ReadOnlyBuilder(state.getChildNode(name));
     }
 
     @Override @Nonnull
-    public NodeBuilder addChild(@Nonnull String name) {
+    public NodeBuilder setChildNode(@Nonnull String name) {
         throw unsupported();
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeBuilderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeBuilderTest.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeBuilderTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeBuilderTest.java Wed Apr 24 10:37:51 2013
@@ -65,7 +65,7 @@ public class KernelNodeBuilderTest {
         assertTrue("child node x/y/z should be present", builder.child("x")
                 .child("y").hasChildNode("z"));
 
-        builder.removeNode("x");
+        builder.removeChildNode("x");
         assertFalse("child node x not should be present",
                 builder.hasChildNode("x"));
         assertFalse("child node x/y not should be present", builder.child("x")

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreTest.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreTest.java Wed Apr 24 10:37:51 2013
@@ -83,7 +83,7 @@ public class KernelNodeStoreTest {
         NodeBuilder testBuilder = rootBuilder.child("test");
         NodeBuilder newNodeBuilder = testBuilder.child("newNode");
 
-        testBuilder.removeNode("x");
+        testBuilder.removeChildNode("x");
 
         newNodeBuilder.setProperty("n", 42);
 
@@ -138,7 +138,7 @@ public class KernelNodeStoreTest {
 
         newNodeBuilder.setProperty("n", 42);
 
-        testBuilder.removeNode("a");
+        testBuilder.removeChildNode("a");
 
         NodeState newRoot = rootBuilder.getNodeState();
 
@@ -168,7 +168,7 @@ public class KernelNodeStoreTest {
 
         newNodeBuilder.setProperty("n", 42);
 
-        testBuilder.removeNode("a");
+        testBuilder.removeChildNode("a");
 
         NodeState newRoot = rootBuilder.getNodeState();
 
@@ -273,7 +273,7 @@ public class KernelNodeStoreTest {
         branch = store.branch();
         root = branch.getHead().builder();
         parent = root.child("parent");
-        parent.removeNode("child-moved");
+        parent.removeChildNode("child-moved");
         branch.setRoot(root.getNodeState());
         branch.merge(EmptyHook.INSTANCE);
 

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java Wed Apr 24 10:37:51 2013
@@ -73,7 +73,7 @@ public class NodeTypeIndexTest {
         NodeStoreBranch branch = store.branch();
         NodeBuilder root = branch.getHead().builder();
 
-        root.removeNode("rep:security"); // interferes with tests
+        root.removeChildNode("rep:security"); // interferes with tests
         addFolder(root, "folder-1");
         addFolder(root, "folder-2");
         addFile(root, "file-1");

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java Wed Apr 24 10:37:51 2013
@@ -382,7 +382,7 @@ public class Property2IndexTest {
                 .setProperty("foo", "abc");
         NodeState before = builder.getNodeState();
         builder = before.builder();
-        builder.removeNode("b");
+        builder.removeChildNode("b");
         NodeState after = builder.getNodeState();
 
         CommitFailedException unexpected = EditorDiff.process(

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilderTest.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilderTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilderTest.java Wed Apr 24 10:37:51 2013
@@ -32,7 +32,6 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
 public class MemoryNodeBuilderTest {
@@ -112,7 +111,7 @@ public class MemoryNodeBuilderTest {
             NodeBuilder root = base.builder();
             NodeBuilder child = root.child(name);
 
-            root.removeNode(name);
+            root.removeChildNode(name);
             try {
                 child.getChildNodeCount();
                 fail();
@@ -131,7 +130,7 @@ public class MemoryNodeBuilderTest {
             NodeBuilder root = base.builder();
             NodeBuilder child = root.child(name);
 
-            root.removeNode(name);
+            root.removeChildNode(name);
             try {
                 child.setProperty("q", "w");
                 fail();
@@ -148,7 +147,7 @@ public class MemoryNodeBuilderTest {
     public void testAddRemovedNodeAgain() {
         NodeBuilder root = base.builder();
 
-        root.removeNode("x");
+        root.removeChildNode("x");
         NodeBuilder x = root.child("x");
 
         x.child("q");
@@ -193,12 +192,11 @@ public class MemoryNodeBuilderTest {
         NodeBuilder m = root.child("m");
         NodeBuilder n = m.child("n");
 
-        root.removeNode("m");
+        root.removeChildNode("m");
         n.hasChildNode("any");
     }
 
     @Test
-    @Ignore("OAK-781")
     public void testExistingStatus() {
         NodeBuilder root = base.builder();
         NodeBuilder x = root.child("x");
@@ -220,11 +218,10 @@ public class MemoryNodeBuilderTest {
     }
 
     @Test
-    @Ignore("OAK-781")
     public void testRemovedStatus() {
         NodeBuilder root = base.builder();
         NodeBuilder x = root.child("x");
-        root.removeNode("x");
+        root.removeChildNode("x");
         assertFalse(x.isConnected());
         try {
             assertTrue(x.exists());
@@ -251,27 +248,24 @@ public class MemoryNodeBuilderTest {
     }
 
     @Test
-    @Ignore("OAK-781")
     public void getExistingChildTest() {
         NodeBuilder rootBuilder = base.builder();
-        NodeBuilder x = rootBuilder.getChild("x");
+        NodeBuilder x = rootBuilder.getChildNode("x");
         assertTrue(x.exists());
         assertTrue(x.getNodeState().exists());
     }
 
     @Test
-    @Ignore("OAK-781")
     public void getNonExistingChildTest() {
         NodeBuilder rootBuilder = base.builder();
-        NodeBuilder any = rootBuilder.getChild("any");
-        assertFalse(any.exists());
-        assertFalse(any.getNodeState().exists());
+        NodeBuilder any = rootBuilder.getChildNode("any");
+        assertFalse(any.isConnected());
     }
 
     @Test
     public void addExistingChildTest() {
         NodeBuilder rootBuilder = base.builder();
-        NodeBuilder x = rootBuilder.addChild("x");
+        NodeBuilder x = rootBuilder.setChildNode("x");
         assertTrue(x.exists());
         assertTrue(x.getBaseState().exists());
     }
@@ -279,7 +273,7 @@ public class MemoryNodeBuilderTest {
     @Test
     public void addNewChildTest() {
         NodeBuilder rootBuilder = base.builder();
-        NodeBuilder x = rootBuilder.addChild("any");
+        NodeBuilder x = rootBuilder.setChildNode("any");
         assertTrue(x.exists());
         assertTrue(x.getNodeState().exists());
     }
@@ -305,7 +299,7 @@ public class MemoryNodeBuilderTest {
         NodeBuilder rootBuilder = EMPTY_NODE.builder();
 
         // +"/a":{"c":{"c"="cValue"}}
-        rootBuilder.setNode("a", createBC(true));
+        rootBuilder.setChildNode("a", createBC(true));
 
         NodeState c = rootBuilder.getNodeState().getChildNode("a").getChildNode("c");
         assertTrue(c.hasProperty("c"));
@@ -320,7 +314,7 @@ public class MemoryNodeBuilderTest {
     @Test
     public void assertion_OAK781() {
         NodeBuilder rootBuilder = EMPTY_NODE.builder();
-        rootBuilder.child("a").setNode("b", createBC(false));
+        rootBuilder.child("a").setChildNode("b", createBC(false));
 
         NodeState r = rootBuilder.getNodeState();
         NodeState a = r.getChildNode("a");
@@ -341,12 +335,11 @@ public class MemoryNodeBuilderTest {
     }
 
     @Test
-    @Ignore("OAK-781")
     public void modifyChildNodeOfNonExistingNode() {
         NodeBuilder rootBuilder = EMPTY_NODE.builder();
 
         // +"/a":{"b":{"c":{"c"="cValue"}}} where b.exists() == false
-        rootBuilder.child("a").setNode("b", createBC(false));
+        rootBuilder.child("a").setChildNode("b", createBC(false));
 
         NodeState r = rootBuilder.getNodeState();
         NodeState a = r.getChildNode("a");
@@ -358,7 +351,7 @@ public class MemoryNodeBuilderTest {
         assertTrue(c.exists());
         assertTrue(c.hasProperty("c"));
 
-        rootBuilder.child("a").getChild("b").child("c").setProperty("c2", "c2Value");
+        rootBuilder.child("a").getChildNode("b").child("c").setProperty("c2", "c2Value");
 
         r = rootBuilder.getNodeState();
         a = r.getChildNode("a");
@@ -379,7 +372,7 @@ public class MemoryNodeBuilderTest {
         NodeBuilder rootBuilder = EMPTY_NODE.builder();
 
         // +"/a":{"b":{"c":{"c"="cValue"}}} where b.exists() == false
-        rootBuilder.child("a").setNode("b", createBC(false));
+        rootBuilder.child("a").setChildNode("b", createBC(false));
 
         NodeState r = rootBuilder.getNodeState();
         NodeState a = r.getChildNode("a");
@@ -391,7 +384,7 @@ public class MemoryNodeBuilderTest {
         assertTrue(c.exists());
         assertTrue(c.hasProperty("c"));
 
-        rootBuilder.child("a").addChild("b").child("c").setProperty("c2", "c2Value");
+        rootBuilder.child("a").setChildNode("b").child("c").setProperty("c2", "c2Value");
 
         r = rootBuilder.getNodeState();
         a = r.getChildNode("a");
@@ -408,12 +401,11 @@ public class MemoryNodeBuilderTest {
     }
 
     @Test
-    @Ignore("OAK-781")
     public void shadowNonExistingNode2() {
         NodeBuilder rootBuilder = EMPTY_NODE.builder();
 
         // +"/a":{"b":{"c":{"c":"cValue"}}} where b.exists() == false
-        rootBuilder.child("a").setNode("b", createBC(false));
+        rootBuilder.child("a").setChildNode("b", createBC(false));
 
         NodeState r = rootBuilder.getNodeState();
         NodeState a = r.getChildNode("a");

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorTest.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/nodetype/TypeEditorTest.java Wed Apr 24 10:37:51 2013
@@ -48,7 +48,7 @@ public class TypeEditorTest {
         hook.processCommit(before, after);
 
         before = after;
-        builder.removeNode(":hidden");
+        builder.removeChildNode(":hidden");
         after = builder.getNodeState();
         hook.processCommit(before, after);
     }

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompareAgainstBaseStateTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompareAgainstBaseStateTest.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompareAgainstBaseStateTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompareAgainstBaseStateTest.java Wed Apr 24 10:37:51 2013
@@ -136,7 +136,7 @@ public class CompareAgainstBaseStateTest
     @Test
     public void testChildNodeDeleted() {
         NodeState before = persist(builder);
-        builder.removeNode("baz");
+        builder.removeChildNode("baz");
         NodeState after = persist(builder);
 
         diff.childNodeDeleted("baz", before.getChildNode("baz"));

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/RecordTest.java Wed Apr 24 10:37:51 2013
@@ -306,7 +306,7 @@ public class RecordTest {
 
         builder = before.builder();
         for (int i = 0; i < 900; i++) {
-            builder.removeNode("test" + i);
+            builder.removeChildNode("test" + i);
         }
         NodeState after = writer.writeNode(builder.getNodeState());
         writer.flush();

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/ReadOnlyOakDirectory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/ReadOnlyOakDirectory.java?rev=1471355&r1=1471354&r2=1471355&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/ReadOnlyOakDirectory.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/ReadOnlyOakDirectory.java Wed Apr 24 10:37:51 2013
@@ -60,7 +60,7 @@ class ReadOnlyOakDirectory extends Direc
 
     @Override
     public void deleteFile(String name) throws IOException {
-        directoryBuilder.removeNode(name);
+        directoryBuilder.removeChildNode(name);
     }
 
     @Override