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 2012/04/26 12:03:32 UTC

svn commit: r1330741 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/api/ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/ oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/ oak-jcr/src/main/java/org/apache/ja...

Author: mduerig
Date: Thu Apr 26 10:03:31 2012
New Revision: 1330741

URL: http://svn.apache.org/viewvc?rev=1330741&view=rev
Log:
OAK-18: Define Oak API
- alternative implementation which implements a fully persisted transient space (WIP)

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelTree2.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Tree.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRoot.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelRootFuzzIT.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelRootTest.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeDelegate.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Tree.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Tree.java?rev=1330741&r1=1330740&r2=1330741&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Tree.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Tree.java Thu Apr 26 10:03:31 2012
@@ -120,7 +120,7 @@ public interface Tree {
      * the returned iterable.
      * @return  An {@code Iterable} for all property states
      */
-    Iterable<PropertyState> getProperties();
+    Iterable<? extends PropertyState> getProperties();
 
     /**
      * Get a child of this {@code ContentTree} instance

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateBuilder.java?rev=1330741&r1=1330740&r2=1330741&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStateBuilder.java Thu Apr 26 10:03:31 2012
@@ -42,8 +42,7 @@ public class KernelNodeStateBuilder impl
     public static NodeStateBuilder create(MicroKernel kernel, CoreValueFactory valueFactory,
             String path, String revision) {
 
-        String[] r = new String[1];
-        r[0] = revision;
+        String[] r = {revision};
         return new KernelNodeStateBuilder(kernel, valueFactory, path, r);
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRoot.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRoot.java?rev=1330741&r1=1330740&r2=1330741&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRoot.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRoot.java Thu Apr 26 10:03:31 2012
@@ -18,13 +18,11 @@
  */
 package org.apache.jackrabbit.oak.kernel;
 
-import org.apache.jackrabbit.mk.util.PathUtils;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.CoreValue;
-import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.kernel.KernelTree.Listener;
+import org.apache.jackrabbit.oak.kernel.KernelTree2.Listener;
 
 import java.util.List;
 
@@ -48,7 +46,7 @@ public class KernelRoot implements Root 
     private NodeState base;
 
     /** Root state of this tree */
-    private KernelTree root;
+    private KernelTree2 root;
 
     /** Listener for changes on the content tree */
     private TreeListener treeListener = new TreeListener();
@@ -59,18 +57,18 @@ public class KernelRoot implements Root 
         this.store = store;
         this.workspaceName = workspaceName;
         this.base = store.getRoot().getChildNode(workspaceName);
-        this.root = new KernelTree(base, treeListener);
         nodeStateBuilder = store.getBuilder(base);
+        this.root = new KernelTree2(store, nodeStateBuilder, treeListener);
     }
 
     @Override
     public boolean move(String sourcePath, String destPath) {
-        KernelTree source = getTransientState(sourcePath);
+        KernelTree2 source = getTransientState(sourcePath);
         if (source == null) {
             return false;
         }
 
-        KernelTree destParent = getTransientState(getParentPath(destPath));
+        KernelTree2 destParent = getTransientState(getParentPath(destPath));
         String destName = getName(destPath);
         return destParent != null && source.move(destParent, destName);
 
@@ -78,12 +76,12 @@ public class KernelRoot implements Root 
 
     @Override
     public boolean copy(String sourcePath, String destPath) {
-        KernelTree sourceNode = getTransientState(sourcePath);
+        KernelTree2 sourceNode = getTransientState(sourcePath);
         if (sourceNode == null) {
             return false;
         }
 
-        KernelTree destParent = getTransientState(getParentPath(destPath));
+        KernelTree2 destParent = getTransientState(getParentPath(destPath));
         String destName = getName(destPath);
         return destParent != null && sourceNode.copy(destParent, destName);
 
@@ -105,7 +103,7 @@ public class KernelRoot implements Root 
         base = store.getRoot().getChildNode(workspaceName);
         nodeStateBuilder = store.getBuilder(base);
         treeListener = new TreeListener();
-        root = new KernelTree(base, treeListener);
+        root = new KernelTree2(store, nodeStateBuilder, treeListener);
     }
 
     @Override
@@ -122,8 +120,8 @@ public class KernelRoot implements Root 
      * @return  a {@link KernelTree} instance for the item
      *          at {@code path} or {@code null} if no such item exits.
      */
-    private KernelTree getTransientState(String path) {
-        KernelTree state = root;
+    private KernelTree2 getTransientState(String path) {
+        KernelTree2 state = root;
         for (String name : elements(path)) {
             state = state.getChild(name);
             if (state == null) {
@@ -133,59 +131,42 @@ public class KernelRoot implements Root 
         return state;
     }
 
+    // TODO accumulate change log for refresh/rebase
     private class TreeListener implements Listener {
         private boolean isDirty;
-        
+
         @Override
-        public void addChild(KernelTree tree, String name) {
-            NodeStateBuilder target = getBuilder(tree);
-            target.addNode(name);
+        public void addChild(KernelTree2 tree, String name) {
             isDirty = true;
         }
 
         @Override
-        public void removeChild(KernelTree tree, String name) {
-            NodeStateBuilder target = getBuilder(tree);
-            target.removeNode(name);
+        public void removeChild(KernelTree2 tree, String name) {
             isDirty = true;
         }
 
         @Override
-        public void setProperty(KernelTree tree, String name, CoreValue value) {
-            NodeStateBuilder target = getBuilder(tree);
-            PropertyState propertyState = new KernelPropertyState(name, value);
-            target.setProperty(propertyState);
+        public void setProperty(KernelTree2 tree, String name, CoreValue value) {
             isDirty = true;
         }
 
         @Override
-        public void setProperty(KernelTree tree, String name, List<CoreValue> values) {
-            NodeStateBuilder target = getBuilder(tree);
-            PropertyState propertyState = new KernelPropertyState(name, values);
-            target.setProperty(propertyState);
+        public void setProperty(KernelTree2 tree, String name, List<CoreValue> values) {
             isDirty = true;
         }
 
         @Override
-        public void removeProperty(KernelTree tree, String name) {
-            NodeStateBuilder target = getBuilder(tree);
-            target.removeProperty(name);
+        public void removeProperty(KernelTree2 tree, String name) {
             isDirty = true;
         }
 
         @Override
-        public void move(KernelTree tree, String name, KernelTree moved) {
-            NodeStateBuilder source = getBuilder(tree).getChildBuilder(name);
-            NodeStateBuilder destParent = getBuilder(moved.getParent());
-            source.moveTo(destParent, moved.getName());
+        public void move(KernelTree2 tree, String name, KernelTree2 moved) {
             isDirty = true;
         }
 
         @Override
-        public void copy(KernelTree tree, String name, KernelTree copied) {
-            NodeStateBuilder source = getBuilder(tree).getChildBuilder(name);
-            NodeStateBuilder destParent = getBuilder(copied.getParent());
-            source.copyTo(destParent, copied.getName());
+        public void copy(KernelTree2 tree, String name, KernelTree2 copied) {
             isDirty = true;
         }
 
@@ -194,13 +175,4 @@ public class KernelRoot implements Root 
         }
     }
 
-    private NodeStateBuilder getBuilder(Tree tree) {
-        String path = tree.getPath();
-        NodeStateBuilder builder = nodeStateBuilder;
-        for (String name : PathUtils.elements(path)) {
-            builder = builder.getChildBuilder(name);
-        }
-        
-        return builder;
-    }
 }

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelTree2.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelTree2.java?rev=1330741&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelTree2.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelTree2.java Thu Apr 26 10:03:31 2012
@@ -0,0 +1,422 @@
+/*
+ * 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.kernel;
+
+import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.util.Function1;
+import org.apache.jackrabbit.oak.util.Iterators;
+import org.apache.jackrabbit.oak.util.PagedIterator;
+
+import java.util.Iterator;
+import java.util.List;
+
+import static org.apache.jackrabbit.oak.util.Iterators.flatten;
+
+public class KernelTree2 implements Tree {
+
+    private final NodeStore store;
+
+    /**
+     * Underlying persistent state or {@code null} if this instance represents an
+     * added content tree
+     */
+    private final NodeState baseState;
+
+    private final NodeStateBuilder builder;
+
+    /** Listener for changes on this content tree */
+    private final Listener listener;
+
+    /** Name of this content tree */
+    private String name;
+
+    /** Parent of this content tree */
+    private KernelTree2 parent;
+
+    private KernelTree2(NodeStore store, NodeState baseState, NodeStateBuilder builder,
+            KernelTree2 parent, String name, Listener listener) {
+
+        this.store = store;
+        this.builder = builder;
+        this.baseState = baseState;
+        this.listener = listener;
+        this.name = name;
+        this.parent = parent;
+    }
+    
+    KernelTree2(NodeStore store, NodeStateBuilder nodeStateBuilder, Listener listener) {
+        this(store, nodeStateBuilder.getNodeState(), nodeStateBuilder, null, "", listener);
+    }
+
+    /**
+     * Listener for changes on {@code ContentTree}s
+     */
+    interface Listener {
+
+        /**
+         * The child of the given {@code name} has been added to {@code tree}.
+         * @param tree  parent to which a child was added
+         * @param name  name of the added child
+         */
+        void addChild(KernelTree2 tree, String name);
+
+        /**
+         * The child of the given {@code name} has been removed from {@code tree}
+         * @param tree  parent from which a child was removed
+         * @param name  name of the removed child
+         */
+        void removeChild(KernelTree2 tree, String name);
+
+        /**
+         * The property of the given {@code name} and {@code value} has been set.
+         * @param tree  parent on which the property was set.
+         * @param name  name of the property
+         * @param value  value of the property
+         */
+        void setProperty(KernelTree2 tree, String name, CoreValue value);
+
+        /**
+         * The property of the given {@code name} and {@code values} has been set.
+         * @param tree  parent on which the property was set.
+         * @param name  name of the property
+         * @param values  values of the property
+         */
+        void setProperty(KernelTree2 tree, String name, List<CoreValue> values);
+
+        /**
+         * The property of the given {@code name} has been removed.
+         * @param tree  parent on which the property was removed.
+         * @param name  name of the property
+         */
+        void removeProperty(KernelTree2 tree, String name);
+
+        /**
+         * The child with the given {@code name} has been moved.
+         * @param tree  parent from which the child was moved
+         * @param name  name of the moved child
+         * @param moved  moved child
+         */
+        void move(KernelTree2 tree, String name, KernelTree2 moved);
+
+        /**
+         * The child with the given {@code name} been copied.
+         * @param tree  parent from which the child way copied
+         * @param name  name of the copied child
+         * @param copied  copied child
+         */
+        void copy(KernelTree2 tree, String name, KernelTree2 copied);
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getPath() {
+        if (parent == null) {
+            return name;
+        }
+        else {
+            String path = parent.getPath();
+            return path.isEmpty()
+                    ? name
+                    : path + '/' + name;
+        }
+    }
+
+    @Override
+    public Tree getParent() {
+        return parent;
+    }
+
+    @Override
+    public PropertyState getProperty(String name) {
+        return getNodeState().getProperty(name);
+    }
+
+    @Override
+    public Status getPropertyStatus(String name) {
+        if (baseState == null) {
+            if (hasProperty(name)) {
+                return Status.NEW;
+            }
+            else {
+                return null;
+            }
+        }
+        else {
+            if (hasProperty(name)) {
+                if (baseState.getProperty(name) == null) {
+                    return Status.NEW;
+                }
+                else {
+                    PropertyState base = baseState.getProperty(name);
+                    PropertyState head = getProperty(name);
+                    if (base.equals(head)) {
+                        return Status.EXISTING;
+                    }
+                    else {
+                        return Status.MODIFIED;
+                    }
+                }
+            }
+            else {
+                if (baseState.getProperty(name) == null) {
+                    return null;
+                }
+                else {
+                    return Status.REMOVED;
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean hasProperty(String name) {
+        return getNodeState().getProperty(name) != null;
+    }
+
+    @Override
+    public long getPropertyCount() {
+        return getNodeState().getPropertyCount();
+    }
+
+    @Override
+    public Iterable<? extends PropertyState> getProperties() {
+        return getNodeState().getProperties();
+    }
+
+    @Override
+    public KernelTree2 getChild(String name) {
+        NodeStateBuilder childBuilder = builder.getChildBuilder(name);
+        NodeState childBaseState = baseState == null
+            ? null
+            : baseState.getChildNode(name);
+
+        return childBuilder == null
+            ? null
+            : new KernelTree2(store, childBaseState, childBuilder, this, name, listener);
+    }
+
+    @Override
+    public Status getChildStatus(String name) {
+        if (baseState == null) {
+            if (hasChild(name)) {
+                return Status.NEW;
+            }
+            else {
+                return null;
+            }
+        }
+        else {
+            if (hasChild(name)) {
+                if (baseState.getChildNode(name) == null) {
+                    return Status.NEW;
+                }
+                else {
+                    if (equals(baseState, getNodeState())) {
+                        return Status.EXISTING;
+                    }
+                    else {
+                        return Status.MODIFIED;
+                    }
+                }
+            }
+            else {
+                if (baseState.getChildNode(name) == null) {
+                    return null;
+                }
+                else {
+                    return Status.REMOVED;
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean hasChild(String name) {
+        return getNodeState().getChildNode(name) != null;
+    }
+
+    @Override
+    public long getChildrenCount() {
+        return getNodeState().getChildNodeCount();
+    }
+
+    @Override
+    public Iterable<Tree> getChildren() {
+        return new Iterable<Tree>() {
+            @Override
+            public Iterator<Tree> iterator() {
+
+                Iterator<? extends ChildNodeEntry> childEntries = flatten(
+                    new PagedIterator<ChildNodeEntry>(1024) {
+                        @Override
+                        protected Iterator<? extends ChildNodeEntry> getPage(long pos, int size) {
+                            return getNodeState().getChildNodeEntries(pos, size).iterator();
+                        }
+                    });
+
+                return Iterators.map(childEntries, new Function1<ChildNodeEntry, Tree>() {
+                    @Override
+                    public Tree apply(ChildNodeEntry entry) {
+                        NodeStateBuilder childBuilder = builder.getChildBuilder(entry.getName());
+                        return new KernelTree2(store, childBuilder.getNodeState(), childBuilder, KernelTree2.this, entry.getName(), listener);
+                    }
+                });
+            }
+        };
+    }
+
+    @Override
+    public Tree addChild(String name) {
+        NodeStateBuilder childBuilder = builder.addNode(name);
+        KernelTree2 added = new KernelTree2(store, null, childBuilder, this, name, listener);
+        if (added != null) {
+            listener.addChild(this, name);
+        }
+        return added;
+    }
+
+    @Override
+    public boolean removeChild(String name) {
+        boolean result = builder.removeNode(name);
+        if (result) {
+            listener.removeChild(this, name);
+        }
+        return result;
+    }
+
+    @Override
+    public void setProperty(String name, CoreValue value) {
+        PropertyState propertyState = new KernelPropertyState(name, value);
+        builder.setProperty(propertyState);
+        if (listener != null) {
+            listener.setProperty(this, name, value);
+        }
+    }
+
+    @Override
+    public void setProperty(String name, List<CoreValue> values) {
+        PropertyState propertyState = new KernelPropertyState(name, values);
+        builder.setProperty(propertyState);
+        if (listener != null) {
+            listener.setProperty(this, name, values);
+        }
+    }
+
+    @Override
+    public void removeProperty(String name) {
+        builder.removeProperty(name);
+        if (listener != null) {
+            listener.removeProperty(this, name);
+        }
+    }
+
+    /**
+     * Move this tree to the parent at {@code destParent} with the new name
+     * {@code destName}.
+     *
+     * @param destParent  new parent for this tree
+     * @param destName  new name for this tree
+     * @return  {@code true} if successful, {@code false otherwise}. I.e.
+     * when {@code destName} already exists at {@code destParent}
+     */
+    public boolean move(KernelTree2 destParent, String destName) {
+        boolean result = builder.moveTo(destParent.builder, destName);
+        if (result) {
+            KernelTree2 oldParent = parent;
+            String oldName = name;
+
+            name = destName;
+            parent = destParent;
+
+            if (listener != null) {
+                listener.move(oldParent, oldName, this);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Copy this tree to the parent at {@code destParent} with the name {@code destName}.
+     *
+     * @param destParent  parent for the copied tree
+     * @param destName  name for the copied tree
+     * @return  {@code true} if successful, {@code false otherwise}. I.e.
+     * when {@code destName} already exists at {@code destParent}
+     */
+    public boolean copy(KernelTree2 destParent, String destName) {
+        boolean result = builder.copyTo(destParent.builder, destName);
+        if (result) {
+            if (listener != null) {
+                // FIXME call listener listener.copy(parent, name, copy);
+            }
+            return true;
+        }
+        return result;
+    }
+
+    //------------------------------------------------------------< private >---
+
+    private NodeState getNodeState() {
+        return builder.getNodeState();
+    }
+
+    private boolean equals(NodeState state1, NodeState state2) {
+        final boolean[] isDirty = {false};
+        store.compare(state1, state2, new NodeStateDiff() {
+            @Override
+            public void propertyAdded(PropertyState after) {
+                isDirty[0] = true;
+            }
+
+            @Override
+            public void propertyChanged(PropertyState before, PropertyState after) {
+                isDirty[0] = true;
+            }
+
+            @Override
+            public void propertyDeleted(PropertyState before) {
+                isDirty[0] = true;
+            }
+
+            @Override
+            public void childNodeAdded(String name, NodeState after) {
+                isDirty[0] = true;
+            }
+
+            @Override
+            public void childNodeChanged(String name, NodeState before, NodeState after) {
+                isDirty[0] = true;  // FIXME cut transitivity here
+            }
+
+            @Override
+            public void childNodeDeleted(String name, NodeState before) {
+                isDirty[0] = true;
+            }
+        });
+
+        return !isDirty[0];
+    }
+
+}

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelRootFuzzIT.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelRootFuzzIT.java?rev=1330741&r1=1330740&r2=1330741&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelRootFuzzIT.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelRootFuzzIT.java Thu Apr 26 10:03:31 2012
@@ -75,13 +75,13 @@ public class KernelRootFuzzIT {
     public void setup() {
         counter = 0;
 
-        MicroKernel mk1 = new MicroKernelImpl("./target/mk1");
+        MicroKernel mk1 = new MicroKernelImpl("./target/mk1/" + random.nextInt());
         vf = new CoreValueFactoryImpl(mk1);
         store1 = new KernelNodeStore(mk1, vf);
         mk1.commit("", "+\"/test\":{} +\"/test/root\":{}", mk1.getHeadRevision(), "");
         root1 = new KernelRoot(store1, "test");
 
-        MicroKernel mk2 = new MicroKernelImpl("./target/mk2");
+        MicroKernel mk2 = new MicroKernelImpl("./target/mk2/" + random.nextInt());
         store2 = new KernelNodeStore(mk2, vf);
         mk2.commit("", "+\"/test\":{} +\"/test/root\":{}", mk2.getHeadRevision(), "");
         root2 = new KernelRoot(store2, "test");

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelRootTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelRootTest.java?rev=1330741&r1=1330740&r2=1330741&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelRootTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelRootTest.java Thu Apr 26 10:03:31 2012
@@ -22,6 +22,7 @@ import org.apache.jackrabbit.oak.api.Com
 import org.apache.jackrabbit.oak.api.CoreValue;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Tree.Status;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -114,7 +115,7 @@ public class KernelRootTest extends Abst
         expectedProperties.put("b", valueFactory.createValue(2));
         expectedProperties.put("c", valueFactory.createValue(3));
 
-        Iterable<PropertyState> properties = tree.getProperties();
+        Iterable<? extends PropertyState> properties = tree.getProperties();
         for (PropertyState property : properties) {
             CoreValue value = expectedProperties.remove(property.getName());
             assertNotNull(value);
@@ -334,6 +335,78 @@ public class KernelRootTest extends Abst
     }
 
     @Test
+    public void addAndRemoveProperty() throws CommitFailedException {
+        KernelRoot root = new KernelRoot(store, "test");
+        Tree tree = root.getTree("/");
+
+        tree.setProperty("P0", valueFactory.createValue("V1"));
+        root.commit();
+        tree = root.getTree("/");
+        assertTrue(tree.hasProperty("P0"));
+
+        tree.removeProperty("P0");
+        root.commit();
+        tree = root.getTree("/");
+        assertFalse(tree.hasProperty("P0"));
+    }
+    
+    @Test
+    public void nodeStatus() throws CommitFailedException {
+        KernelRoot root = new KernelRoot(store, "test");
+        Tree tree = root.getTree("/");
+
+        tree.addChild("new");
+        assertEquals(Status.NEW, tree.getChildStatus("new"));
+        root.commit();
+
+        tree = root.getTree("/");
+        assertEquals(Status.EXISTING, tree.getChildStatus("new"));
+        Tree added = tree.getChild("new");
+        added.addChild("another");
+        assertEquals(Status.MODIFIED, tree.getChildStatus("new"));
+        root.commit();
+
+        tree = root.getTree("/");
+        assertEquals(Status.EXISTING, tree.getChildStatus("new"));
+        tree.getChild("new").removeChild("another");
+        assertEquals(Status.MODIFIED, tree.getChildStatus("new"));
+        assertEquals(Status.REMOVED, tree.getChild("new").getChildStatus("another"));
+        root.commit();
+
+        tree = root.getTree("/");
+        assertEquals(Status.EXISTING, tree.getChildStatus("new"));
+        assertNull(tree.getChild("new").getChild("another"));
+        assertNull(tree.getChild("new").getChildStatus("another"));
+    }
+
+    @Test
+    public void propertyStatus() throws CommitFailedException {
+        KernelRoot root = new KernelRoot(store, "test");
+        Tree tree = root.getTree("/");
+        CoreValue value1 = valueFactory.createValue("V1");
+        CoreValue value2 = valueFactory.createValue("V2");
+
+        tree.setProperty("new", value1);
+        assertEquals(Status.NEW, tree.getPropertyStatus("new"));
+        root.commit();
+
+        tree = root.getTree("/");
+        assertEquals(Status.EXISTING, tree.getPropertyStatus("new"));
+        tree.setProperty("new", value2);
+        assertEquals(Status.MODIFIED, tree.getPropertyStatus("new"));
+        root.commit();
+
+        tree = root.getTree("/");
+        assertEquals(Status.EXISTING, tree.getPropertyStatus("new"));
+        tree.removeProperty("new");
+        assertEquals(Status.REMOVED, tree.getPropertyStatus("new"));
+        root.commit();
+
+        tree = root.getTree("/");
+        assertNull(tree.getPropertyStatus("new"));
+    }
+
+    @Test
     @Ignore("WIP") // FIXME: causes OOME since the branch/merge feature from OAK-45 is used
     public void largeChildList() throws CommitFailedException {
         KernelRoot root = new KernelRoot(store, "test");

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeDelegate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeDelegate.java?rev=1330741&r1=1330740&r2=1330741&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeDelegate.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeDelegate.java Thu Apr 26 10:03:31 2012
@@ -16,14 +16,6 @@
  */
 package org.apache.jackrabbit.oak.jcr;
 
-import java.util.Iterator;
-import java.util.List;
-
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.Node;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.RepositoryException;
-
 import org.apache.jackrabbit.oak.api.CoreValue;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Root;
@@ -33,6 +25,12 @@ import org.apache.jackrabbit.oak.namepat
 import org.apache.jackrabbit.oak.util.Function1;
 import org.apache.jackrabbit.oak.util.Iterators;
 
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import java.util.Iterator;
+import java.util.List;
+
 public class NodeDelegate {
 
     private final SessionContext<SessionImpl> sessionContext;
@@ -178,7 +176,7 @@ public class NodeDelegate {
     }
 
     private Iterator<PropertyDelegate> propertyDelegateIterator(
-            Iterator<PropertyState> properties) {
+            Iterator<? extends PropertyState> properties) {
         return Iterators.map(properties,
                 new Function1<PropertyState, PropertyDelegate>() {
                     @Override