Author: mreutegg
Date: Fri Feb 21 21:40:35 2014
New Revision: 1570718

URL: http://svn.apache.org/r1570718
Log:
OAK-1461: Merge DocumentNodeState with Node

Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitDiff.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Node.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentSplitTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MeasureMemory.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoDocumentStoreTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/SimpleTest.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
 Fri Feb 21 21:40:35 2014
@@ -110,7 +110,7 @@ public class Commit {
     }
     
     void addNodeDiff(Node n) {
-        diff.tag('+').key(n.path);
+        diff.tag('+').key(n.getPath());
         diff.object();
         n.append(diff, false);
         diff.endObject();
@@ -135,13 +135,14 @@ public class Commit {
     }
 
     void addNode(Node n) {
-        if (operations.containsKey(n.path)) {
-            String msg = "Node already added: " + n.path;
+        String path = n.getPath();
+        if (operations.containsKey(path)) {
+            String msg = "Node already added: " + path;
             LOG.error(msg);
             throw new MicroKernelException(msg);
         }
-        operations.put(n.path, n.asOperation(true));
-        addedNodes.add(n.path);
+        operations.put(path, n.asOperation(true));
+        addedNodes.add(path);
     }
 
     boolean isEmpty() {

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitDiff.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitDiff.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitDiff.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/CommitDiff.java
 Fri Feb 21 21:40:35 2014
@@ -36,6 +36,8 @@ import static org.apache.jackrabbit.oak.
  */
 class CommitDiff implements NodeStateDiff {
 
+    private final DocumentNodeStore store;
+
     private final Commit commit;
 
     private final String path;
@@ -44,12 +46,15 @@ class CommitDiff implements NodeStateDif
 
     private final BlobSerializer blobs;
 
-    CommitDiff(@Nonnull Commit commit, @Nonnull BlobSerializer blobs) {
-        this(checkNotNull(commit), "/", new JsopBuilder(), 
checkNotNull(blobs));
+    CommitDiff(@Nonnull DocumentNodeStore store, @Nonnull Commit commit,
+               @Nonnull BlobSerializer blobs) {
+        this(checkNotNull(store), checkNotNull(commit), "/",
+                new JsopBuilder(), checkNotNull(blobs));
     }
 
-    private CommitDiff(Commit commit, String path,
+    private CommitDiff(DocumentNodeStore store, Commit commit, String path,
                JsopBuilder builder, BlobSerializer blobs) {
+        this.store = store;
         this.commit = commit;
         this.path = path;
         this.builder = builder;
@@ -77,9 +82,9 @@ class CommitDiff implements NodeStateDif
     @Override
     public boolean childNodeAdded(String name, NodeState after) {
         String p = PathUtils.concat(path, name);
-        commit.addNode(new Node(p, commit.getRevision()));
+        commit.addNode(new DocumentNodeState(store, p, commit.getRevision()));
         return after.compareAgainstBaseState(EMPTY_NODE,
-                new CommitDiff(commit, p, builder, blobs));
+                new CommitDiff(store, commit, p, builder, blobs));
     }
 
     @Override
@@ -88,7 +93,7 @@ class CommitDiff implements NodeStateDif
                                     NodeState after) {
         String p = PathUtils.concat(path, name);
         return after.compareAgainstBaseState(before,
-                new CommitDiff(commit, p, builder, blobs));
+                new CommitDiff(store, commit, p, builder, blobs));
     }
 
     @Override
@@ -96,7 +101,7 @@ class CommitDiff implements NodeStateDif
         String p = PathUtils.concat(path, name);
         commit.removeNode(p);
         return MISSING_NODE.compareAgainstBaseState(before,
-                new CommitDiff(commit, p, builder, blobs));
+                new CommitDiff(store, commit, p, builder, blobs));
     }
 
     //----------------------------< internal 
>----------------------------------

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
 Fri Feb 21 21:40:35 2014
@@ -416,8 +416,8 @@ public class DocumentMK implements Micro
         }
     }
 
-    private static void parseAddNode(Commit commit, JsopReader t, String path) 
{
-        Node n = new Node(path, commit.getRevision());
+    private void parseAddNode(Commit commit, JsopReader t, String path) {
+        Node n = new DocumentNodeState(nodeStore, path, commit.getRevision());
         if (!t.matches('}')) {
             do {
                 String key = t.readString();

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
 Fri Feb 21 21:40:35 2014
@@ -18,15 +18,22 @@ package org.apache.jackrabbit.oak.plugin
 
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Set;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.json.JsopBuilder;
 import org.apache.jackrabbit.oak.commons.json.JsopReader;
 import org.apache.jackrabbit.oak.commons.json.JsopTokenizer;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.commons.json.JsopWriter;
+import org.apache.jackrabbit.oak.kernel.JsonSerializer;
+import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
 import org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState;
@@ -40,15 +47,15 @@ import org.apache.jackrabbit.oak.spi.sta
 import com.google.common.base.Function;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Iterators;
+import com.google.common.collect.Maps;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static 
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
 
 /**
  * A {@link NodeState} implementation for the {@link DocumentNodeStore}.
- * TODO: merge DocumentNodeState with Node
  */
-final class DocumentNodeState extends AbstractNodeState {
+class DocumentNodeState extends AbstractNodeState implements Node {
 
     /**
      * The number of child nodes to fetch initially.
@@ -68,24 +75,32 @@ final class DocumentNodeState extends Ab
 
     private final DocumentNodeStore store;
 
-    private final Node node;
+    final String path;
+    final Revision rev;
+    final Map<String, PropertyState> properties = Maps.newHashMap();
+    Revision lastRevision;
+    final boolean hasChildren;
 
     /**
      * TODO: OAK-1056
      */
     private boolean isBranch;
 
-    DocumentNodeState(@Nonnull DocumentNodeStore store, @Nonnull Node node) {
-        this.store = checkNotNull(store);
-        this.node = checkNotNull(node);
+    DocumentNodeState(@Nonnull DocumentNodeStore store, @Nonnull String path,
+                      @Nonnull Revision rev) {
+        this(store, path, rev, false);
     }
 
-    String getPath() {
-        return node.getPath();
+    DocumentNodeState(@Nonnull DocumentNodeStore store, @Nonnull String path,
+                      @Nonnull Revision rev, boolean hasChildren) {
+        this.store = checkNotNull(store);
+        this.path = checkNotNull(path);
+        this.rev = checkNotNull(rev);
+        this.hasChildren = hasChildren;
     }
 
     Revision getRevision() {
-        return node.getReadRevision();
+        return rev;
     }
 
     DocumentNodeState setBranch() {
@@ -106,7 +121,7 @@ final class DocumentNodeState extends Ab
         } else if (that instanceof DocumentNodeState) {
             DocumentNodeState other = (DocumentNodeState) that;
             if (getPath().equals(other.getPath())) {
-                return 
node.getLastRevision().equals(other.node.getLastRevision());
+                return lastRevision.equals(other.lastRevision);
             }
         } else if (that instanceof ModifiedNodeState) {
             ModifiedNodeState modified = (ModifiedNodeState) that;
@@ -128,66 +143,57 @@ final class DocumentNodeState extends Ab
 
     @Override
     public PropertyState getProperty(String name) {
-        String value = node.getProperty(name);
-        if (value == null) {
-            return null;
-        }
-        return new DocumentPropertyState(store, name, value);
+        return properties.get(name);
     }
 
     @Override
     public boolean hasProperty(String name) {
-        return node.getPropertyNames().contains(name);
+        return properties.containsKey(name);
     }
 
     @Nonnull
     @Override
     public Iterable<? extends PropertyState> getProperties() {
-        return Iterables.transform(node.getPropertyNames(), new 
Function<String, PropertyState>() {
-            @Override
-            public PropertyState apply(String name) {
-                return getProperty(name);
-            }
-        });
+        return properties.values();
     }
 
     @Override
     public boolean hasChildNode(String name) {
-        if (node.hasNoChildren() || !isValidName(name)) {
+        if (!hasChildren || !isValidName(name)) {
             return false;
         } else {
             String p = PathUtils.concat(getPath(), name);
-            return store.getNode(p, node.getLastRevision()) != null;
+            return store.getNode(p, lastRevision) != null;
         }
     }
 
     @Nonnull
     @Override
     public NodeState getChildNode(@Nonnull String name) {
-        if (node.hasNoChildren()) {
+        if (!hasChildren) {
             checkValidName(name);
             return EmptyNodeState.MISSING_NODE;
         }
         String p = PathUtils.concat(getPath(), name);
-        Node child = store.getNode(p, node.getLastRevision());
+        DocumentNodeState child = store.getNode(p, lastRevision);
         if (child == null) {
             checkValidName(name);
             return EmptyNodeState.MISSING_NODE;
         } else {
-            return new DocumentNodeState(store, child);
+            return child;
         }
     }
 
     @Override
     public long getChildNodeCount(long max) {
-        if (node.hasNoChildren()) {
+        if (!hasChildren) {
             return 0;
         }
         if (max > DocumentNodeStore.NUM_CHILDREN_CACHE_LIMIT) {
             // count all
             return Iterators.size(new ChildNodeEntryIterator());
         }
-        Node.Children c = store.getChildren(node, null, (int) max);
+        Node.Children c = store.getChildren(this, null, (int) max);
         if (c.hasMore) {
             return Long.MAX_VALUE;
         } else {
@@ -199,7 +205,7 @@ final class DocumentNodeState extends Ab
     @Nonnull
     @Override
     public Iterable<? extends ChildNodeEntry> getChildNodeEntries() {
-        if (node.hasNoChildren()) {
+        if (!hasChildren) {
             return Collections.emptyList();
         }
         return new Iterable<ChildNodeEntry>() {
@@ -233,12 +239,12 @@ final class DocumentNodeState extends Ab
             DocumentNodeState mBase = (DocumentNodeState) base;
             if (store == mBase.store) {
                 if (getPath().equals(mBase.getPath())) {
-                    if 
(node.getLastRevision().equals(mBase.node.getLastRevision())) {
+                    if (lastRevision.equals(mBase.lastRevision)) {
                         // no differences
                         return true;
                     } else if (getChildNodeCount(LOCAL_DIFF_THRESHOLD) > 
LOCAL_DIFF_THRESHOLD) {
                         // use DocumentNodeStore compare when there are many 
children
-                        return dispatch(store.diffChildren(this.node, 
mBase.node), mBase, diff);
+                        return dispatch(store.diffChildren(this, mBase), 
mBase, diff);
                     }
                 }
             }
@@ -247,6 +253,131 @@ final class DocumentNodeState extends Ab
         return super.compareAgainstBaseState(base, diff);
     }
 
+    //----------------------------< Node 
>--------------------------------------
+
+    @Override
+    public void setProperty(String propertyName, String value) {
+        if (value == null) {
+            properties.remove(propertyName);
+        } else {
+            properties.put(propertyName,
+                    new DocumentPropertyState(store, propertyName, value));
+        }
+    }
+
+    @Override
+    public void setProperty(PropertyState property) {
+        properties.put(property.getName(), property);
+    }
+
+    @Override
+    public String getPropertyAsString(String propertyName) {
+        PropertyState prop = properties.get(propertyName);
+        if (prop == null) {
+            return null;
+        }
+        JsopBuilder builder = new JsopBuilder();
+        new JsonSerializer(builder, store.getBlobSerializer()).serialize(prop);
+        return builder.toString();
+    }
+
+    @Override
+    public Set<String> getPropertyNames() {
+        return properties.keySet();
+    }
+
+    @Override
+    public void copyTo(Node newNode) {
+        for (Map.Entry<String, PropertyState> entry : properties.entrySet()) {
+            newNode.setProperty(entry.getValue());
+        }
+    }
+
+    @Override
+    public boolean hasNoChildren() {
+        return !hasChildren;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buff = new StringBuilder();
+        buff.append("path: ").append(path).append('\n');
+        buff.append("rev: ").append(rev).append('\n');
+        buff.append(properties);
+        buff.append('\n');
+        return buff.toString();
+    }
+
+    /**
+     * Create an add node operation for this node.
+     */
+    @Override
+    public UpdateOp asOperation(boolean isNew) {
+        String id = Utils.getIdFromPath(path);
+        UpdateOp op = new UpdateOp(id, isNew);
+        op.set(Document.ID, id);
+        NodeDocument.setModified(op, rev);
+        NodeDocument.setDeleted(op, rev, false);
+        for (String p : properties.keySet()) {
+            String key = Utils.escapePropertyName(p);
+            op.setMapEntry(key, rev, getPropertyAsString(p));
+        }
+        return op;
+    }
+
+    @Override
+    public String getPath() {
+        return path;
+    }
+
+    @Override
+    public String getId() {
+        return path + "@" + lastRevision;
+    }
+
+    @Override
+    public void append(JsopWriter json, boolean includeId) {
+        if (includeId) {
+            json.key(":id").value(getId());
+        }
+        for (String p : properties.keySet()) {
+            json.key(p).encodedValue(getPropertyAsString(p));
+        }
+    }
+
+    @Override
+    public void setLastRevision(Revision lastRevision) {
+        this.lastRevision = lastRevision;
+    }
+
+    @Override
+    public Revision getLastRevision() {
+        return lastRevision;
+    }
+
+    @Override
+    public int getMemory() {
+        int size = 180 + path.length() * 2;
+        // rough approximation for properties
+        for (Map.Entry<String, PropertyState> entry : properties.entrySet()) {
+            // name
+            size += 48 + entry.getKey().length() * 2;
+            PropertyState propState = entry.getValue();
+            if (propState.getType() != Type.BINARY
+                    && propState.getType() != Type.BINARIES) {
+                // assume binaries go into blob store
+                for (int i = 0; i < propState.count(); i++) {
+                    // size() returns length of string
+                    // overhead:
+                    // - 8 bytes per reference in values list
+                    // - 48 bytes per string
+                    size += 56 + propState.size(i) * 2;
+                }
+            }
+        }
+        return size;
+    }
+
     //------------------------------< internal 
>--------------------------------
 
     private boolean dispatch(@Nonnull String jsonDiff,
@@ -338,21 +469,21 @@ final class DocumentNodeState extends Ab
     @Nonnull
     private Iterable<ChildNodeEntry> getChildNodeEntries(@Nullable String name,
                                                          int limit) {
-        Iterable<Node> children = store.getChildNodes(node, name, limit);
-        return Iterables.transform(children, new Function<Node, 
ChildNodeEntry>() {
+        Iterable<DocumentNodeState> children = store.getChildNodes(this, name, 
limit);
+        return Iterables.transform(children, new Function<DocumentNodeState, 
ChildNodeEntry>() {
             @Override
-            public ChildNodeEntry apply(final Node input) {
+            public ChildNodeEntry apply(final DocumentNodeState input) {
                 return new AbstractChildNodeEntry() {
                     @Nonnull
                     @Override
                     public String getName() {
-                        return PathUtils.getName(input.path);
+                        return PathUtils.getName(input.getPath());
                     }
 
                     @Nonnull
                     @Override
                     public NodeState getNodeState() {
-                        return new DocumentNodeState(store, input);
+                        return input;
                     }
                 };
             }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
 Fri Feb 21 21:40:35 2014
@@ -55,6 +55,7 @@ import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
 import org.apache.jackrabbit.mk.api.MicroKernelException;
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 import org.apache.jackrabbit.oak.commons.json.JsopStream;
 import org.apache.jackrabbit.oak.commons.json.JsopWriter;
@@ -84,7 +85,7 @@ import org.slf4j.LoggerFactory;
  */
 public final class DocumentNodeStore
         implements NodeStore, RevisionContext, Observable {
-    
+
     private static final Logger LOG = 
LoggerFactory.getLogger(DocumentNodeStore.class);
 
     /**
@@ -116,6 +117,11 @@ public final class DocumentNodeStore
     protected final DocumentStore store;
 
     /**
+     * Marker node, indicating a node does not exist at a given revision.
+     */
+    protected final DocumentNodeState missing;
+
+    /**
      * The commit queue to coordinate the commits.
      */
     protected final CommitQueue commitQueue;
@@ -218,9 +224,9 @@ public final class DocumentNodeStore
     /**
      * The node cache.
      *
-     * Key: PathRev, value: Node
+     * Key: PathRev, value: DocumentNodeState
      */
-    private final Cache<CacheValue, Node> nodeCache;
+    private final Cache<CacheValue, DocumentNodeState> nodeCache;
     private final CacheStats nodeCacheStats;
 
     /**
@@ -299,6 +305,12 @@ public final class DocumentNodeStore
         this.revisionComparator = new Revision.RevisionComparator(clusterId);
         this.branches = new UnmergedBranches(getRevisionComparator());
         this.asyncDelay = builder.getAsyncDelay();
+        this.missing = new DocumentNodeState(this, "MISSING", new Revision(0, 
0, 0)) {
+            @Override
+            public int getMemory() {
+                return 8;
+            }
+        };
 
         //TODO Make stats collection configurable as it add slight overhead
 
@@ -323,7 +335,7 @@ public final class DocumentNodeStore
             // root node is missing: repository is not initialized
             Revision head = newRevision();
             Commit commit = new Commit(this, null, head);
-            Node n = new Node("/", head);
+            Node n = new DocumentNodeState(this, "/", head);
             commit.addNode(n);
             commit.applyToDocumentStore();
             // use dummy Revision as before
@@ -570,21 +582,21 @@ public final class DocumentNodeStore
      *          given revision.
      */
     @CheckForNull
-    Node getNode(@Nonnull final String path, @Nonnull final Revision rev) {
+    DocumentNodeState getNode(@Nonnull final String path, @Nonnull final 
Revision rev) {
         checkRevisionAge(checkNotNull(rev), checkNotNull(path));
         try {
             PathRev key = new PathRev(path, rev);
-            Node node = nodeCache.get(key, new Callable<Node>() {
+            DocumentNodeState node = nodeCache.get(key, new 
Callable<DocumentNodeState>() {
                 @Override
-                public Node call() throws Exception {
-                    Node n = readNode(path, rev);
+                public DocumentNodeState call() throws Exception {
+                    DocumentNodeState n = readNode(path, rev);
                     if (n == null) {
-                        n = Node.MISSING;
+                        n = missing;
                     }
                     return n;
                 }
             });
-            return node == Node.MISSING ? null : node;
+            return node == missing ? null : node;
         } catch (ExecutionException e) {
             throw new MicroKernelException(e);
         }
@@ -755,9 +767,9 @@ public final class DocumentNodeStore
      * @return the child nodes.
      */
     @Nonnull
-    Iterable<Node> getChildNodes(final @Nonnull Node parent,
-                                 final @Nullable String name,
-                                 final int limit) {
+    Iterable<DocumentNodeState> getChildNodes(final @Nonnull Node parent,
+                                              final @Nullable String name,
+                                              final int limit) {
         // Preemptive check. If we know there are no children then
         // return straight away
         if (checkNotNull(parent).hasNoChildren()) {
@@ -766,16 +778,16 @@ public final class DocumentNodeStore
 
         final Revision readRevision = parent.getLastRevision();
         return Iterables.transform(getChildren(parent, name, limit).children,
-                new Function<String, Node>() {
+                new Function<String, DocumentNodeState>() {
             @Override
-            public Node apply(String input) {
+            public DocumentNodeState apply(String input) {
                 return getNode(input, readRevision);
             }
         });
     }
 
     @CheckForNull
-    Node readNode(String path, Revision readRevision) {
+    DocumentNodeState readNode(String path, Revision readRevision) {
         String id = Utils.getIdFromPath(path);
         Revision lastRevision = getPendingModifications().get(path);
         NodeDocument doc = store.find(Collection.NODES, id);
@@ -935,12 +947,12 @@ public final class DocumentNodeStore
      */
     @Nonnull
     DocumentNodeState getRoot(@Nonnull Revision revision) {
-        Node root = getNode("/", revision);
+        DocumentNodeState root = getNode("/", revision);
         if (root == null) {
             throw new IllegalStateException(
                     "root node does not exist at revision " + revision);
         }
-        return new DocumentNodeState(this, root);
+        return root;
     }
 
     @Nonnull
@@ -1091,7 +1103,8 @@ public final class DocumentNodeStore
      * @param base the base node to compare against.
      * @return the json diff.
      */
-    String diffChildren(final @Nonnull Node node, final @Nonnull Node base) {
+    String diffChildren(final @Nonnull DocumentNodeState node,
+                        final @Nonnull DocumentNodeState base) {
         PathRev key = diffCacheKey(node.getPath(),
                 base.getLastRevision(), node.getLastRevision());
         try {
@@ -1118,8 +1131,8 @@ public final class DocumentNodeStore
         }
         Revision fromRev = Revision.fromString(fromRevisionId);
         Revision toRev = Revision.fromString(toRevisionId);
-        final Node from = getNode(path, fromRev);
-        final Node to = getNode(path, toRev);
+        final DocumentNodeState from = getNode(path, fromRev);
+        final DocumentNodeState to = getNode(path, toRev);
         if (from == null || to == null) {
             // TODO implement correct behavior if the node does't/didn't exist
             String msg = String.format("Diff is only supported if the node 
exists in both cases. " +
@@ -1379,30 +1392,32 @@ public final class DocumentNodeStore
 
     //-----------------------------< internal 
>---------------------------------
 
-    private static void diffProperties(Node from, Node to, JsopWriter w) {
-        for (String name : from.getPropertyNames()) {
+    private static void diffProperties(DocumentNodeState from,
+                                       DocumentNodeState to,
+                                       JsopWriter w) {
+        for (PropertyState fromValue : from.getProperties()) {
+            String name = fromValue.getName();
             // changed or removed properties
-            String fromValue = from.getProperty(name);
-            String toValue = to.getProperty(name);
+            PropertyState toValue = to.getProperty(name);
             if (!fromValue.equals(toValue)) {
                 w.tag('^').key(PathUtils.concat(from.getPath(), name));
                 if (toValue == null) {
                     w.value(null);
                 } else {
-                    w.encodedValue(toValue).newline();
+                    w.encodedValue(to.getPropertyAsString(name)).newline();
                 }
             }
         }
         for (String name : to.getPropertyNames()) {
             // added properties
-            if (from.getProperty(name) == null) {
+            if (!from.hasProperty(name)) {
                 w.tag('^').key(PathUtils.concat(from.getPath(), name))
-                        .encodedValue(to.getProperty(name)).newline();
+                        .encodedValue(to.getPropertyAsString(name)).newline();
             }
         }
     }
 
-    private String diffImpl(Node from, Node to)
+    private String diffImpl(DocumentNodeState from, DocumentNodeState to)
             throws MicroKernelException {
         JsopWriter w = new JsopStream();
         diffProperties(from, to, w);
@@ -1554,7 +1569,7 @@ public final class DocumentNodeStore
         // of this commit i.e. transient nodes. If its required it would need 
to be looked
         // into
 
-        Node newNode = new Node(targetPath, commit.getRevision());
+        Node newNode = new DocumentNodeState(this, targetPath, 
commit.getRevision());
         source.copyTo(newNode);
 
         commit.addNode(newNode);

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBranch.java
 Fri Feb 21 21:40:35 2014
@@ -86,7 +86,7 @@ public class DocumentNodeStoreBranch
             @Override
             public void with(Commit c) {
                 toPersist.compareAgainstBaseState(base,
-                        new CommitDiff(c, store.getBlobSerializer()));
+                        new CommitDiff(store, c, store.getBlobSerializer()));
             }
         }, base, info);
         if (base.isBranch()) {

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Node.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Node.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Node.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Node.java
 Fri Feb 21 21:40:35 2014
@@ -17,138 +17,47 @@
 package org.apache.jackrabbit.oak.plugins.document;
 
 import java.util.ArrayList;
-import java.util.Map;
 import java.util.Set;
-import java.util.Map.Entry;
 
-import org.apache.jackrabbit.oak.commons.json.JsopWriter;
+import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.cache.CacheValue;
-import org.apache.jackrabbit.oak.plugins.document.util.Utils;
+import org.apache.jackrabbit.oak.commons.json.JsopWriter;
 
 /**
  * Represents a node held in memory (in the cache for example).
  */
-public class Node implements CacheValue {
-    /**
-     * A node, which does not exist at a given revision.
-     */
-    static final Node MISSING = new Node(null, null) {
-        @Override
-        public int getMemory() {
-            return 8;
-        }
-    };
+public interface Node extends CacheValue {
 
-    final String path;
-    final Revision rev;
-    final Map<String, String> properties = Utils.newMap();
-    Revision lastRevision;
-    final boolean hasChildren;
-    
-    Node(String path, Revision rev) {
-        this(path, rev, false);
-    }
+    Children NO_CHILDREN = new Children();
 
-    Node(String path, Revision rev, boolean hasChildren) {
-        this.path = path;
-        this.rev = rev;
-        this.hasChildren = hasChildren;
-    }
-    
-    void setProperty(String propertyName, String value) {
-        if (value == null) {
-            properties.remove(propertyName);
-        } else {
-            properties.put(propertyName, value);
-        }
-    }
-    
-    public String getProperty(String propertyName) {
-        return properties.get(propertyName);
-    }
-    
-    public Set<String> getPropertyNames() {
-        return properties.keySet();
-    }
+    String getPropertyAsString(String propertyName);
 
-    public void copyTo(Node newNode) {
-        newNode.properties.putAll(properties);
-    }
+    void setProperty(String propertyName, String value);
 
-    public boolean hasNoChildren() {
-        return !hasChildren;
-    }
+    void setProperty(PropertyState property);
 
-    @Override
-    public String toString() {
-        StringBuilder buff = new StringBuilder();
-        buff.append("path: ").append(path).append('\n');
-        buff.append("rev: ").append(rev).append('\n');
-        buff.append(properties);
-        buff.append('\n');
-        return buff.toString();
-    }
-    
-    /**
-     * Create an add node operation for this node.
-     */
-    UpdateOp asOperation(boolean isNew) {
-        String id = Utils.getIdFromPath(path);
-        UpdateOp op = new UpdateOp(id, isNew);
-        op.set(Document.ID, id);
-        NodeDocument.setModified(op, rev);
-        NodeDocument.setDeleted(op, rev, false);
-        for (String p : properties.keySet()) {
-            String key = Utils.escapePropertyName(p);
-            op.setMapEntry(key, rev, properties.get(p));
-        }
-        return op;
-    }
+    Set<String> getPropertyNames();
 
-    String getPath() {
-        return path;
-    }
+    void copyTo(Node newNode);
 
-    Revision getReadRevision() {
-        return rev;
-    }
+    boolean hasNoChildren();
 
-    public String getId() {
-        return path + "@" + lastRevision;        
-    }
+    String getId();
 
-    public void append(JsopWriter json, boolean includeId) {
-        if (includeId) {
-            json.key(":id").value(getId());
-        }
-        for (String p : properties.keySet()) {
-            json.key(p).encodedValue(properties.get(p));
-        }
-    }
+    void append(JsopWriter json, boolean includeId);
 
-    public void setLastRevision(Revision lastRevision) {
-        this.lastRevision = lastRevision;
-    }
+    void setLastRevision(Revision lastRevision);
 
-    public Revision getLastRevision() {
-        return lastRevision;
-    }
-    
-    @Override
-    public int getMemory() {
-        int size = 180 + path.length() * 2;
-        for (Entry<String, String> e : properties.entrySet()) {
-            size += 136 + e.getKey().length() * 2 + e.getValue().length() * 2;
-        }
-        return size;
-    }
+    Revision getLastRevision();
 
-    static final Children NO_CHILDREN = new Children();
+    String getPath();
+
+    UpdateOp asOperation(boolean isNew);
 
     /**
      * A list of children for a node.
      */
-    static class Children implements CacheValue {
+    public static class Children implements CacheValue {
 
         final ArrayList<String> children = new ArrayList<String>();
         boolean hasMore;
@@ -166,7 +75,5 @@ public class Node implements CacheValue 
         public String toString() {
             return children.toString();
         }
-        
     }
-
 }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
 Fri Feb 21 21:40:35 2014
@@ -451,9 +451,10 @@ public class NodeDocument extends Docume
     }
 
     /**
-     * Returns a {@link Node} as seen at the given <code>readRevision</code>.
+     * Returns a {@link DocumentNodeState} as seen at the given
+     * <code>readRevision</code>.
      *
-     * @param context      the revision context.
+     * @param nodeStore    the node store.
      * @param readRevision the read revision.
      * @param lastModified the revision when this node was last modified, but
      *                     the value is potentially not yet reflected in this
@@ -463,35 +464,35 @@ public class NodeDocument extends Docume
      *         given read revision.
      */
     @CheckForNull
-    public Node getNodeAtRevision(@Nonnull RevisionContext context,
-                                  @Nonnull Revision readRevision,
-                                  @Nullable Revision lastModified) {
+    public DocumentNodeState getNodeAtRevision(@Nonnull DocumentNodeStore 
nodeStore,
+                                               @Nonnull Revision readRevision,
+                                               @Nullable Revision 
lastModified) {
         Set<Revision> validRevisions = new HashSet<Revision>();
-        Revision min = getLiveRevision(context, readRevision, validRevisions);
+        Revision min = getLiveRevision(nodeStore, readRevision, 
validRevisions);
         if (min == null) {
             // deleted
             return null;
         }
         String path = Utils.getPathFromId(getId());
-        Node n = new Node(path, readRevision, hasChildren());
+        DocumentNodeState n = new DocumentNodeState(nodeStore, path, 
readRevision, hasChildren());
         Revision lastRevision = min;
         for (String key : keySet()) {
             if (!Utils.isPropertyName(key)) {
                 continue;
             }
             // first check local map, which contains most recent values
-            Value value = getLatestValue(context, getLocalMap(key),
+            Value value = getLatestValue(nodeStore, getLocalMap(key),
                     min, readRevision, validRevisions);
             if (value == null && !getPreviousRanges().isEmpty()) {
                 // check complete revision history
-                value = getLatestValue(context, getValueMap(key),
+                value = getLatestValue(nodeStore, getValueMap(key),
                         min, readRevision, validRevisions);
             }
             String propertyName = Utils.unescapePropertyName(key);
             String v = value != null ? value.value : null;
             n.setProperty(propertyName, v);
             // keep track of when this node was last modified
-            if (value != null && isRevisionNewer(context, value.revision, 
lastRevision)) {
+            if (value != null && isRevisionNewer(nodeStore, value.revision, 
lastRevision)) {
                 lastRevision = value.revision;
             }
         }
@@ -502,11 +503,11 @@ public class NodeDocument extends Docume
         // _lastRev.
 
         // when was this node last modified?
-        Branch branch = context.getBranches().getBranch(readRevision);
+        Branch branch = nodeStore.getBranches().getBranch(readRevision);
         Map<Integer, Revision> lastRevs = Maps.newHashMap(getLastRev());
         // overlay with unsaved last modified from this instance
         if (lastModified != null) {
-            lastRevs.put(context.getClusterId(), lastModified);
+            lastRevs.put(nodeStore.getClusterId(), lastModified);
         }
         Revision branchBase = null;
         if (branch != null) {
@@ -514,7 +515,7 @@ public class NodeDocument extends Docume
         }
         for (Revision r : lastRevs.values()) {
             // ignore if newer than readRevision
-            if (isRevisionNewer(context, r, readRevision)) {
+            if (isRevisionNewer(nodeStore, r, readRevision)) {
                 // the node has a _lastRev which is newer than readRevision
                 // this means we don't know when this node was
                 // modified by an operation on a descendant node between
@@ -522,7 +523,7 @@ public class NodeDocument extends Docume
                 // to stay on the safe side and use readRevision
                 lastRevision = readRevision;
                 continue;
-            } else if (branchBase != null && isRevisionNewer(context, r, 
branchBase)) {
+            } else if (branchBase != null && isRevisionNewer(nodeStore, r, 
branchBase)) {
                 // readRevision is on a branch and the node has a
                 // _lastRev which is newer than the base of the branch
                 // we cannot use this _lastRev because it is not visible
@@ -530,7 +531,7 @@ public class NodeDocument extends Docume
                 // changes is the base of the branch
                 r = branchBase;
             }
-            if (isRevisionNewer(context, r, lastRevision)) {
+            if (isRevisionNewer(nodeStore, r, lastRevision)) {
                 lastRevision = r;
             }
         }

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterTest.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterTest.java
 Fri Feb 21 21:40:35 2014
@@ -36,6 +36,8 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.DefaultNodeStateDiff;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -109,8 +111,12 @@ public class ClusterTest {
 
         String r1b = mk1.getHeadRevision();
         String n1b = mk1.getNodes("/test", r1b, 0, 0, 10, null);
+        JSONParser parser = new JSONParser();
+        JSONObject obj = (JSONObject) parser.parse(n1b);
         // mk1 now sees both changes
-        assertEquals("{\"x\":1,\"y\":2,\":childNodeCount\":0}", n1b);
+        assertEquals(1L, obj.get("x"));
+        assertEquals(2L, obj.get("y"));
+        assertEquals(0L, obj.get(":childNodeCount"));
 
         mk1.dispose();
         mk2.dispose();

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentSplitTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentSplitTest.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentSplitTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentSplitTest.java
 Fri Feb 21 21:40:35 2014
@@ -262,7 +262,7 @@ public class DocumentSplitTest extends B
             Revision lastRev = ns.getPendingModifications().get("/test");
             Node n = doc.getNodeAtRevision(mk.getNodeStore(), head, lastRev);
             assertNotNull(n);
-            String value = n.getProperty(name);
+            String value = n.getPropertyAsString(name);
             // set or increment
             if (value == null) {
                 value = String.valueOf(0);

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MeasureMemory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MeasureMemory.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MeasureMemory.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MeasureMemory.java
 Fri Feb 21 21:40:35 2014
@@ -36,6 +36,9 @@ public class MeasureMemory {
     static final int TEST_COUNT = 10000;
     static final int OVERHEAD = 24;
 
+    static final DocumentNodeStore STORE = new DocumentMK.Builder()
+            .setAsyncDelay(0).getNodeStore();
+
     @Test
     public void overhead() throws Exception {
         measureMemory(new Callable<Object[]>() {
@@ -150,9 +153,10 @@ public class MeasureMemory {
     }
     
     static Node generateNode(int propertyCount) {
-        Node n = new Node(new String("/hello/world"), new Revision(1, 2, 3));
+        Node n = new DocumentNodeState(STORE, new String("/hello/world"),
+                new Revision(1, 2, 3));
         for (int i = 0; i < propertyCount; i++) {
-            n.setProperty("property" + i, "values " + i);
+            n.setProperty("property" + i, "\"values " + i + "\"");
         }
         n.setLastRevision(new Revision(1, 2, 3));
         return n;

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoDocumentStoreTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoDocumentStoreTest.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoDocumentStoreTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoDocumentStoreTest.java
 Fri Feb 21 21:40:35 2014
@@ -190,10 +190,12 @@ public class MongoDocumentStoreTest {
     @Test
     public void queryWithLimit() throws Exception {
         DocumentStore docStore = openDocumentStore();
+        DocumentNodeStore store = new DocumentMK.Builder()
+                .setDocumentStore(docStore).setAsyncDelay(0).getNodeStore();
         Revision rev = Revision.newRevision(0);
         List<UpdateOp> inserts = new ArrayList<UpdateOp>();
         for (int i = 0; i < DocumentMK.MANY_CHILDREN_THRESHOLD * 2; i++) {
-            Node n = new Node("/node-" + i, rev);
+            Node n = new DocumentNodeState(store, "/node-" + i, rev);
             inserts.add(n.asOperation(true));
         }
         docStore.create(Collection.NODES, inserts);
@@ -201,6 +203,7 @@ public class MongoDocumentStoreTest {
                 Utils.getKeyLowerLimit("/"),  Utils.getKeyUpperLimit("/"),
                 DocumentMK.MANY_CHILDREN_THRESHOLD);
         assertEquals(DocumentMK.MANY_CHILDREN_THRESHOLD, docs.size());
+        store.dispose();
     }
 
     @Test

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/SimpleTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/SimpleTest.java?rev=1570718&r1=1570717&r2=1570718&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/SimpleTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/SimpleTest.java
 Fri Feb 21 21:40:35 2014
@@ -26,6 +26,8 @@ import static org.junit.Assert.fail;
 import java.util.Random;
 
 import org.apache.jackrabbit.mk.api.MicroKernelException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.json.JsopBuilder;
 import org.apache.jackrabbit.oak.plugins.document.Node.Children;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
@@ -71,17 +73,20 @@ public class SimpleTest {
     @Test
     public void addNodeGetNode() {
         DocumentMK mk = new DocumentMK.Builder().open();
+        DocumentStore s = mk.getDocumentStore();
+        DocumentNodeStore ns = mk.getNodeStore();
         Revision rev = Revision.fromString(mk.getHeadRevision());
-        Node n = new Node("/test", rev);
-        n.setProperty("name", "Hello");
+        DocumentNodeState n = new DocumentNodeState(ns, "/test", rev);
+        n.setProperty("name", "\"Hello\"");
         UpdateOp op = n.asOperation(true);
         // mark as commit root
         NodeDocument.setRevision(op, rev, "c");
-        DocumentStore s = mk.getDocumentStore();
-        DocumentNodeStore ns = mk.getNodeStore();
         assertTrue(s.create(Collection.NODES, Lists.newArrayList(op)));
-        Node n2 = ns.getNode("/test", rev);
-        assertEquals("Hello", n2.getProperty("name"));
+        DocumentNodeState n2 = ns.getNode("/test", rev);
+        assertNotNull(n2);
+        PropertyState p = n2.getProperty("name");
+        assertNotNull(p);
+        assertEquals("Hello", p.getValue(Type.STRING));
         mk.dispose();
     }
     


Reply via email to