Author: mreutegg
Date: Tue Oct 23 12:22:25 2012
New Revision: 1401267

URL: http://svn.apache.org/viewvc?rev=1401267&view=rev
Log:
OAK-169: Support orderable nodes
- maintain :childOrder on move and copy
- more tests
- removed OrderedChildrenEditor again

Added:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ConflictHandlerWrapper.java
   (with props)
Removed:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/OrderedChildrenEditor.java
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MergingNodeStateDiff.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/RootTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java
    
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MergingNodeStateDiff.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MergingNodeStateDiff.java?rev=1401267&r1=1401266&r2=1401267&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MergingNodeStateDiff.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MergingNodeStateDiff.java
 Tue Oct 23 12:22:25 2012
@@ -17,11 +17,15 @@
 package org.apache.jackrabbit.oak.core;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.commit.ConflictHandlerWrapper;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryPropertyBuilder;
 import org.apache.jackrabbit.oak.spi.commit.ConflictHandler;
 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;
+import org.apache.jackrabbit.oak.spi.state.PropertyBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -51,7 +55,7 @@ class MergingNodeStateDiff implements No
     static void merge(NodeState fromState, NodeState toState, final 
NodeBuilder target,
             final ConflictHandler conflictHandler) {
         toState.compareAgainstBaseState(fromState, new MergingNodeStateDiff(
-                checkNotNull(target), conflictHandler));
+                checkNotNull(target), new 
ChildOrderConflictHandler(conflictHandler)));
     }
 
     //------------------------------------------------------< NodeStateDiff 
>---
@@ -188,7 +192,7 @@ class MergingNodeStateDiff implements No
         switch (resolution) {
             case OURS:
                 if (n != null) {
-                    target.removeNode(name);
+                    removeChild(target, name);
                 }
                 break;
             case THEIRS:
@@ -204,9 +208,102 @@ class MergingNodeStateDiff implements No
         for (PropertyState property : state.getProperties()) {
             child.setProperty(property);
         }
+        PropertyState childOrder = 
target.getProperty(TreeImpl.OAK_CHILD_ORDER);
+        if (childOrder != null) {
+            PropertyBuilder<String> builder = MemoryPropertyBuilder.create(
+                    Type.STRING, childOrder);
+            builder.addValue(name);
+            target.setProperty(builder.getPropertyState(true));
+        }
         for (ChildNodeEntry entry : state.getChildNodeEntries()) {
             addChild(child, entry.getName(), entry.getNodeState());
         }
     }
 
+    private static void removeChild(NodeBuilder target, String name) {
+        target.removeNode(name);
+        PropertyState childOrder = 
target.getProperty(TreeImpl.OAK_CHILD_ORDER);
+        if (childOrder != null) {
+            PropertyBuilder<String> builder = MemoryPropertyBuilder.create(
+                    Type.STRING, childOrder);
+            builder.removeValue(name);
+            target.setProperty(builder.getPropertyState(true));
+        }
+    }
+
+    /**
+     * <code>ChildOrderConflictHandler</code> ignores conflicts on the
+     * {@link TreeImpl#OAK_CHILD_ORDER} property. All other conflicts are 
forwarded
+     * to the wrapped handler.
+     */
+    private static class ChildOrderConflictHandler extends 
ConflictHandlerWrapper {
+
+        ChildOrderConflictHandler(ConflictHandler delegate) {
+            super(delegate);
+        }
+
+        @Override
+        public Resolution addExistingProperty(NodeBuilder parent,
+                                              PropertyState ours,
+                                              PropertyState theirs) {
+            if (isChildOrderProperty(ours)) {
+                // two sessions concurrently called orderBefore() on a Tree
+                // that was previously unordered.
+                return Resolution.THEIRS;
+            } else {
+                return handler.addExistingProperty(parent, ours, theirs);
+            }
+        }
+
+        @Override
+        public Resolution changeDeletedProperty(NodeBuilder parent,
+                                                PropertyState ours) {
+            if (isChildOrderProperty(ours)) {
+                // orderBefore() on trees that were deleted
+                return Resolution.THEIRS;
+            } else {
+                return handler.changeDeletedProperty(parent, ours);
+            }
+        }
+
+        @Override
+        public Resolution changeChangedProperty(NodeBuilder parent,
+                                                PropertyState ours,
+                                                PropertyState theirs) {
+            if (isChildOrderProperty(ours)) {
+                // concurrent orderBefore(), other changes win
+                return Resolution.THEIRS;
+            } else {
+                return handler.changeChangedProperty(parent, ours, theirs);
+            }
+        }
+
+        @Override
+        public Resolution deleteDeletedProperty(NodeBuilder parent,
+                                                PropertyState ours) {
+            if (isChildOrderProperty(ours)) {
+                // concurrent remove of ordered trees
+                return Resolution.THEIRS;
+            } else {
+                return handler.deleteDeletedProperty(parent, ours);
+            }
+        }
+
+        @Override
+        public Resolution deleteChangedProperty(NodeBuilder parent,
+                                                PropertyState theirs) {
+            if (isChildOrderProperty(theirs)) {
+                // remove trees that were reordered by another session
+                return Resolution.THEIRS;
+            } else {
+                return handler.deleteChangedProperty(parent, theirs);
+            }
+        }
+
+        //----------------------------< internal 
>----------------------------------
+
+        private static boolean isChildOrderProperty(PropertyState p) {
+            return TreeImpl.OAK_CHILD_ORDER.equals(p.getName());
+        }
+    }
 }
\ No newline at end of file

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java?rev=1401267&r1=1401266&r2=1401267&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
 Tue Oct 23 12:22:25 2012
@@ -163,14 +163,23 @@ public class RootImpl implements Root {
 
         purgePendingChanges();
         source.moveTo(destParent, destName);
-        return branch.move(sourcePath, destPath);
+        boolean success = branch.move(sourcePath, destPath);
+        if (success) {
+            getTree(getParentPath(sourcePath)).updateChildOrder();
+            getTree(getParentPath(destPath)).updateChildOrder();
+        }
+        return success;
     }
 
     @Override
     public boolean copy(String sourcePath, String destPath) {
         checkLive();
         purgePendingChanges();
-        return branch.copy(sourcePath, destPath);
+        boolean success = branch.copy(sourcePath, destPath);
+        if (success) {
+            getTree(getParentPath(destPath)).updateChildOrder();
+        }
+        return success;
     }
 
     @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=1401267&r1=1401266&r2=1401267&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
 Tue Oct 23 12:22:25 2012
@@ -21,15 +21,12 @@ package org.apache.jackrabbit.oak.core;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.collect.Iterables;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.TreeLocation;
@@ -41,6 +38,13 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+import org.apache.jackrabbit.oak.spi.state.PropertyBuilder;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -483,6 +487,30 @@ public class TreeImpl implements Tree, P
         return (canRead(child)) ? child : null;
     }
 
+    /**
+     * Update the child order with children that have been removed or added.
+     * Added children are appended to the end of the {@link #OAK_CHILD_ORDER}
+     * property.
+     */
+    void updateChildOrder() {
+        if (!hasOrderableChildren()) {
+            return;
+        }
+        Set<String> names = Sets.newLinkedHashSet();
+        for (String name : getOrderedChildNames()) {
+            if (getNodeBuilder().hasChildNode(name)) {
+                names.add(name);
+            }
+        }
+        for (String name : getNodeBuilder().getChildNodeNames()) {
+            names.add(name);
+        }
+        PropertyBuilder<String> builder = MemoryPropertyBuilder.create(
+                Type.STRING, OAK_CHILD_ORDER);
+        builder.setValues(names);
+        getNodeBuilder().setProperty(builder.getPropertyState(true));
+    }
+
     //------------------------------------------------------------< private 
>---
 
     private TreeImpl internalGetChild(String childName) {

Added: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ConflictHandlerWrapper.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ConflictHandlerWrapper.java?rev=1401267&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ConflictHandlerWrapper.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/ConflictHandlerWrapper.java
 Tue Oct 23 12:22:25 2012
@@ -0,0 +1,95 @@
+/*
+ * 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.commit;
+
+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 wraps another conflict handler
+ * and forwards all calls to the wrapped handler. Sub classes may override
+ * methods of this class and intercept calls they are interested in.
+ */
+public class ConflictHandlerWrapper implements ConflictHandler {
+
+    protected final ConflictHandler handler;
+
+    public ConflictHandlerWrapper(ConflictHandler handler) {
+        this.handler = handler;
+    }
+
+    @Override
+    public Resolution addExistingProperty(NodeBuilder parent,
+                                          PropertyState ours,
+                                          PropertyState theirs) {
+        return handler.addExistingProperty(parent, ours, theirs);
+    }
+
+    @Override
+    public Resolution changeDeletedProperty(NodeBuilder parent,
+                                            PropertyState ours) {
+        return handler.changeDeletedProperty(parent, ours);
+    }
+
+    @Override
+    public Resolution changeChangedProperty(NodeBuilder parent,
+                                            PropertyState ours,
+                                            PropertyState theirs) {
+        return handler.changeChangedProperty(parent, ours, theirs);
+    }
+
+    @Override
+    public Resolution deleteDeletedProperty(NodeBuilder parent,
+                                            PropertyState ours) {
+        return handler.deleteDeletedProperty(parent, ours);
+    }
+
+    @Override
+    public Resolution deleteChangedProperty(NodeBuilder parent,
+                                            PropertyState theirs) {
+        return handler.deleteChangedProperty(parent, theirs);
+    }
+
+    @Override
+    public Resolution addExistingNode(NodeBuilder parent,
+                                      String name,
+                                      NodeState ours,
+                                      NodeState theirs) {
+        return handler.addExistingNode(parent, name, ours, theirs);
+    }
+
+    @Override
+    public Resolution changeDeletedNode(NodeBuilder parent,
+                                        String name,
+                                        NodeState ours) {
+        return handler.changeDeletedNode(parent, name, ours);
+    }
+
+    @Override
+    public Resolution deleteChangedNode(NodeBuilder parent,
+                                        String name,
+                                        NodeState theirs) {
+        return handler.deleteChangedNode(parent, name, theirs);
+    }
+
+    @Override
+    public Resolution deleteDeletedNode(NodeBuilder parent, String name) {
+        return handler.deleteDeletedNode(parent, name);
+    }
+}

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

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

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/RootTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/RootTest.java?rev=1401267&r1=1401266&r2=1401267&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/RootTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/RootTest.java
 Tue Oct 23 12:22:25 2012
@@ -23,7 +23,6 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.commit.ConflictValidator;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import static org.apache.jackrabbit.oak.OakAssert.assertSequence;
@@ -49,7 +48,6 @@ public class RootTest {
     }
 
     @Test
-    @Ignore("OAK-169")
     public void copyOrderableNodes() throws Exception {
         ContentSession s = repository.login(null, null);
         try {
@@ -64,13 +62,15 @@ public class RootTest {
             r.copy("/node3", "/c/node3");
             c = r.getTree("/").getChild("c");
             assertSequence(c.getChildren(), "node1", "node2", "node3");
+            r.commit();
+            c = r.getTree("/").getChild("c");
+            assertSequence(c.getChildren(), "node1", "node2", "node3");
         } finally {
             s.close();
         }
     }
 
     @Test
-    @Ignore("OAK-169")
     public void moveOrderableNodes() throws Exception {
         ContentSession s = repository.login(null, null);
         try {
@@ -85,6 +85,9 @@ public class RootTest {
             r.move("/node3", "/c/node3");
             c = r.getTree("/").getChild("c");
             assertSequence(c.getChildren(), "node1", "node2", "node3");
+            r.commit();
+            c = r.getTree("/").getChild("c");
+            assertSequence(c.getChildren(), "node1", "node2", "node3");
         } finally {
             s.close();
         }

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java?rev=1401267&r1=1401266&r2=1401267&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/api/TreeTest.java
 Tue Oct 23 12:22:25 2012
@@ -90,35 +90,236 @@ public class TreeTest {
     }
 
     @Test
-    public void concurrentAddChildOrderable() throws Exception {
+    public void concurrentOrderBefore() throws Exception {
         ContentSession s1 = repository.login(null, null);
         try {
             Root r1 = s1.getLatestRoot();
             Tree t1 = r1.getTree("/");
-            t1.addChild("node1").orderBefore(null);
+            t1.addChild("node1");
             t1.addChild("node2");
             t1.addChild("node3");
             r1.commit();
+            t1 = r1.getTree("/");
+
             ContentSession s2 = repository.login(null, null);
             try {
                 Root r2 = s2.getLatestRoot();
                 Tree t2 = r2.getTree("/");
 
+                t1.getChild("node2").orderBefore("node1");
+                t1.getChild("node3").orderBefore(null);
+                r1.commit();
                 t1 = r1.getTree("/");
-                // node4 from s1
+                assertSequence(t1.getChildren(), "node2", "node1", "node3");
+
+                t2.getChild("node3").orderBefore("node1");
+                t2.getChild("node2").orderBefore(null);
+                r2.commit();
+                t2 = r2.getTree("/");
+                // other session wins
+                assertSequence(t2.getChildren(), "node2", "node1", "node3");
+
+                // try again on current root
+                t2.getChild("node3").orderBefore("node1");
+                t2.getChild("node2").orderBefore(null);
+                r2.commit();
+                t2 = r2.getTree("/");
+                assertSequence(t2.getChildren(), "node3", "node1", "node2");
+
+            } finally {
+                s2.close();
+            }
+        } finally {
+            s1.close();
+        }
+    }
+
+    @Test
+    public void concurrentOrderBeforeWithAdd() throws Exception {
+        ContentSession s1 = repository.login(null, null);
+        try {
+            Root r1 = s1.getLatestRoot();
+            Tree t1 = r1.getTree("/");
+            t1.addChild("node1");
+            t1.addChild("node2");
+            t1.addChild("node3");
+            r1.commit();
+            t1 = r1.getTree("/");
+
+            ContentSession s2 = repository.login(null, null);
+            try {
+                Root r2 = s2.getLatestRoot();
+                Tree t2 = r2.getTree("/");
+
+                t1.getChild("node2").orderBefore("node1");
+                t1.getChild("node3").orderBefore(null);
                 t1.addChild("node4");
                 r1.commit();
+                t1 = r1.getTree("/");
+                assertSequence(t1.getChildren(), "node2", "node1", "node3", 
"node4");
 
-                // node5 from s2
-                t2.addChild("node5");
-                try {
-                    r2.commit();
-                    // commit must fail
-                } catch (CommitFailedException e) {
-                }
+                t2.getChild("node3").orderBefore("node1");
+                r2.commit();
+                t2 = r2.getTree("/");
+                // other session wins
+                assertSequence(t2.getChildren(), "node2", "node1", "node3", 
"node4");
 
-                r1 = s1.getLatestRoot();
+                // try again on current root
+                t2.getChild("node3").orderBefore("node1");
+                r2.commit();
+                t2 = r2.getTree("/");
+                assertSequence(t2.getChildren(), "node2", "node3", "node1", 
"node4");
+
+            } finally {
+                s2.close();
+            }
+        } finally {
+            s1.close();
+        }
+    }
+
+    @Test
+    public void concurrentOrderBeforeWithRemove() throws Exception {
+        ContentSession s1 = repository.login(null, null);
+        try {
+            Root r1 = s1.getLatestRoot();
+            Tree t1 = r1.getTree("/");
+            t1.addChild("node1");
+            t1.addChild("node2");
+            t1.addChild("node3");
+            t1.addChild("node4");
+            r1.commit();
+            t1 = r1.getTree("/");
+
+            ContentSession s2 = repository.login(null, null);
+            try {
+                Root r2 = s2.getLatestRoot();
+                Tree t2 = r2.getTree("/");
+
+                t1.getChild("node2").orderBefore("node1");
+                t1.getChild("node3").orderBefore(null);
+                t1.getChild("node4").remove();
+                r1.commit();
+                t1 = r1.getTree("/");
+                assertSequence(t1.getChildren(), "node2", "node1", "node3");
+
+                t2.getChild("node3").orderBefore("node1");
+                r2.commit();
+                t2 = r2.getTree("/");
+                // other session wins
+                assertSequence(t2.getChildren(), "node2", "node1", "node3");
+
+                // try again on current root
+                t2.getChild("node3").orderBefore("node1");
+                r2.commit();
+                t2 = r2.getTree("/");
+                assertSequence(t2.getChildren(), "node2", "node3", "node1");
+
+            } finally {
+                s2.close();
+            }
+        } finally {
+            s1.close();
+        }
+    }
+
+    @Test
+    public void concurrentOrderBeforeRemoved() throws Exception {
+        ContentSession s1 = repository.login(null, null);
+        try {
+            Root r1 = s1.getLatestRoot();
+            Tree t1 = r1.getTree("/");
+            t1.addChild("node1");
+            t1.addChild("node2");
+            t1.addChild("node3");
+            r1.commit();
+            t1 = r1.getTree("/");
+
+            ContentSession s2 = repository.login(null, null);
+            try {
+                Root r2 = s2.getLatestRoot();
+                Tree t2 = r2.getTree("/");
+
+                t1.getChild("node2").orderBefore("node1");
+                t1.getChild("node3").remove();
+                r1.commit();
                 t1 = r1.getTree("/");
+                assertSequence(t1.getChildren(), "node2", "node1");
+
+                t2.getChild("node3").orderBefore("node1");
+                r2.commit();
+                t2 = r2.getTree("/");
+                assertSequence(t2.getChildren(), "node2", "node1");
+
+            } finally {
+                s2.close();
+            }
+        } finally {
+            s1.close();
+        }
+    }
+
+    @Test
+    public void concurrentOrderBeforeTargetRemoved() throws Exception {
+        ContentSession s1 = repository.login(null, null);
+        try {
+            Root r1 = s1.getLatestRoot();
+            Tree t1 = r1.getTree("/");
+            t1.addChild("node1").orderBefore(null);
+            t1.addChild("node2");
+            t1.addChild("node3");
+            t1.addChild("node4");
+            r1.commit();
+            t1 = r1.getTree("/");
+
+            ContentSession s2 = repository.login(null, null);
+            try {
+                Root r2 = s2.getLatestRoot();
+                Tree t2 = r2.getTree("/");
+
+                t1.getChild("node2").orderBefore("node1");
+                t1.getChild("node3").remove();
+                r1.commit();
+                t1 = r1.getTree("/");
+                assertSequence(t1.getChildren(), "node2", "node1", "node4");
+
+                t2.getChild("node4").orderBefore("node3");
+                r2.commit();
+                t2 = r2.getTree("/");
+                assertSequence(t2.getChildren(), "node2", "node1", "node4");
+
+            } finally {
+                s2.close();
+            }
+        } finally {
+            s1.close();
+        }
+    }
+
+    @Test
+    public void concurrentAddChildOrderable() throws Exception {
+        ContentSession s1 = repository.login(null, null);
+        try {
+            Root r1 = s1.getLatestRoot();
+            Tree t1 = r1.getTree("/");
+            t1.addChild("node1").orderBefore(null);
+            t1.addChild("node2");
+            r1.commit();
+            ContentSession s2 = repository.login(null, null);
+            try {
+                Root r2 = s2.getLatestRoot();
+                Tree t2 = r2.getTree("/");
+
+                t1 = r1.getTree("/");
+                // node3 from s1
+                t1.addChild("node3");
+                r1.commit();
+
+                // node4 from s2
+                t2.addChild("node4");
+                r2.commit();
+
+                t1 = s1.getLatestRoot().getTree("/");
                 assertSequence(
                         t1.getChildren(), "node1", "node2", "node3", "node4");
             } finally {

Modified: 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java?rev=1401267&r1=1401266&r2=1401267&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/Jcr.java
 Tue Oct 23 12:22:25 2012
@@ -16,9 +16,6 @@
  */
 package org.apache.jackrabbit.oak.jcr;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.DEFAULT_INDEX_HOME;
-
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 
@@ -27,7 +24,6 @@ import javax.jcr.Repository;
 
 import org.apache.jackrabbit.mk.api.MicroKernel;
 import org.apache.jackrabbit.oak.Oak;
-import org.apache.jackrabbit.oak.core.OrderedChildrenEditor;
 import org.apache.jackrabbit.oak.plugins.commit.AnnotatingConflictHandler;
 import org.apache.jackrabbit.oak.plugins.commit.ConflictValidatorProvider;
 import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneHook;
@@ -49,6 +45,9 @@ import org.apache.jackrabbit.oak.spi.lif
 import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.DEFAULT_INDEX_HOME;
+
 public class Jcr {
 
     private final Oak oak;
@@ -75,7 +74,6 @@ public class Jcr {
         with(new PropertyIndexHook());
         with(new LuceneReindexHook(DEFAULT_INDEX_HOME));
         with(new LuceneHook(DEFAULT_INDEX_HOME));
-        with(new OrderedChildrenEditor());
         with(new AnnotatingConflictHandler());
 
         with(new PropertyIndexProvider());

Modified: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java?rev=1401267&r1=1401266&r2=1401267&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/Main.java
 Tue Oct 23 12:22:25 2012
@@ -25,7 +25,6 @@ import org.apache.jackrabbit.mk.api.Micr
 import org.apache.jackrabbit.mk.core.MicroKernelImpl;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.api.ContentRepository;
-import org.apache.jackrabbit.oak.core.OrderedChildrenEditor;
 import org.apache.jackrabbit.oak.http.OakServlet;
 import org.apache.jackrabbit.oak.jcr.RepositoryImpl;
 import org.apache.jackrabbit.oak.plugins.commit.ConflictValidatorProvider;
@@ -207,8 +206,7 @@ public class Main {
                     new ValidatingHook(createDefaultValidatorProvider()),
                     new PropertyIndexHook(),
                     new LuceneReindexHook(DEFAULT_INDEX_HOME),
-                    new LuceneHook(DEFAULT_INDEX_HOME),
-                    new OrderedChildrenEditor());
+                    new LuceneHook(DEFAULT_INDEX_HOME));
         }
 
         private static ValidatorProvider createDefaultValidatorProvider() {


Reply via email to