jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sch...@apache.org
Subject svn commit: r1327432 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/SessionMoveOperation.java test/java/org/apache/jackrabbit/core/ConcurrentCyclicMoveTest.java
Date Wed, 18 Apr 2012 09:23:18 GMT
Author: schans
Date: Wed Apr 18 09:23:18 2012
New Revision: 1327432

URL: http://svn.apache.org/viewvc?rev=1327432&view=rev
Log:
JCR-3291: Prevent the creation of cyclic paths in the transient and persistent states

Added:
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentCyclicMoveTest.java
  (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java?rev=1327432&r1=1327431&r2=1327432&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java
Wed Apr 18 09:23:18 2012
@@ -190,6 +190,10 @@ public class SessionMoveOperation implem
             NodeState destParentState =
                 (NodeState) destParentNode.getOrCreateTransientItemState();
 
+            // Create the transient parent nodes of the target node to prevent 
+            // conflicting and/or cyclic moves. See JCR-3921
+            createTransientParentStates(destParentNode);
+            
             // do move:
             // 1. remove child node entry from old parent
             if (srcParentState.removeChildNodeEntry(targetId)) {
@@ -203,6 +207,12 @@ public class SessionMoveOperation implem
         return this;
     }
 
+    private void createTransientParentStates(NodeImpl node) throws RepositoryException {
+        while (node.getParentId() != null) {
+            node.getOrCreateTransientItemState();
+            node = (NodeImpl) node.getParent();
+        }
+    }
 
     //--------------------------------------------------------------< Object >
 

Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentCyclicMoveTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentCyclicMoveTest.java?rev=1327432&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentCyclicMoveTest.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentCyclicMoveTest.java
Wed Apr 18 09:23:18 2012
@@ -0,0 +1,94 @@
+/*
+ * 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.core;
+
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.core.state.StaleItemStateException;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+
+public class ConcurrentCyclicMoveTest extends AbstractJCRTest {
+
+    private String testRootPath;
+
+    public void testConcurrentSessionMove() throws RepositoryException {
+
+        testRootPath = testRootNode.getPath();
+        Node aa = testRootNode.addNode("a").addNode("aa");
+        Node b = testRootNode.addNode("b");
+        testRootNode.getSession().save();
+
+        String aaId = aa.getIdentifier();
+        String bId= b.getIdentifier();
+        
+        Session session1 = getHelper().getReadWriteSession();
+        Session session2 = getHelper().getReadWriteSession();
+
+        // results in /b/a/aa
+        session1.move(testRootPath + "/a", testRootPath + "/b/a");
+        assertEquals(testRootPath + "/b/a/aa", session1.getNodeByIdentifier(aaId).getPath());
+        
+        // results in a/aa/b
+        session2.move(testRootPath + "/b", testRootPath + "/a/aa/b");
+        assertEquals(testRootPath + "/a/aa/b", session2.getNodeByIdentifier(bId).getPath());
+
+        session1.save();
+
+        // path should not have changed after save.
+        assertEquals(testRootPath + "/a/aa/b", session2.getNodeByIdentifier(bId).getPath());
+
+        try {
+            session2.save();
+            fail("Save should have failed. Possible cyclic persistent path created.");
+        } catch (InvalidItemStateException e) {
+            // expect is a ex caused by a StaleItemStateException with "has been modified
externally"
+            if (!(e.getCause() instanceof StaleItemStateException)) {
+                throw e;
+            }
+        }
+    }
+
+
+    public void testConcurrentWorkspaceMove() throws RepositoryException {
+
+        testRootPath = testRootNode.getPath();
+        testRootNode.addNode("b");
+        Node aa = testRootNode.addNode("a").addNode("aa");
+        testRootNode.getSession().save();
+
+        String aaId = aa.getIdentifier();
+        
+        Session session1 = getHelper().getReadWriteSession();
+        Session session2 = getHelper().getReadWriteSession();
+
+        // results in /b/a/aa
+        session1.getWorkspace().move(testRootPath + "/a", testRootPath + "/b/a");
+        assertEquals(testRootPath + "/b/a/aa", session1.getNodeByIdentifier(aaId).getPath());
+        
+        // try to move b into a/aa (should fail as the above move is persisted
+        try {
+            session2.getWorkspace().move(testRootPath + "/b", testRootPath + "/a/aa/b");
+            fail("Workspace.move() should not have succeeded. Possible cyclic path created.");
+        } catch (PathNotFoundException e) {
+            // expected.
+        }
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentCyclicMoveTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ConcurrentCyclicMoveTest.java
------------------------------------------------------------------------------
    svn:keywords = Id



Mime
View raw message