You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2008/04/07 12:22:48 UTC

svn commit: r645444 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/BatchedItemOperations.java main/java/org/apache/jackrabbit/core/NodeImpl.java test/java/org/apache/jackrabbit/core/ShareableNodeTest.java

Author: dpfister
Date: Mon Apr  7 03:22:47 2008
New Revision: 645444

URL: http://svn.apache.org/viewvc?rev=645444&view=rev
Log:
JCR-1104 - JSR 283 support
- shareble nodes (work in progress)
- versioning operations
- regularize javadoc comments

Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ShareableNodeTest.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java?rev=645444&r1=645443&r2=645444&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java Mon Apr  7 03:22:47 2008
@@ -1170,6 +1170,11 @@
 
         EffectiveNodeType ent = getEffectiveNodeType(node);
 
+        // check shareable
+        if (ent.includesNodeType(NameConstants.MIX_SHAREABLE)) {
+            node.addShare(parent.getNodeId());
+        }
+
         if (!node.getMixinTypeNames().isEmpty()) {
             // create jcr:mixinTypes property
             PropDef pd = ent.getApplicablePropertyDef(NameConstants.JCR_MIXINTYPES,

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java?rev=645444&r1=645443&r2=645444&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java Mon Apr  7 03:22:47 2008
@@ -1738,7 +1738,15 @@
      * @see ItemImpl#getQName()
      */
     public Name getQName() throws RepositoryException {
-        return session.getHierarchyManager().getName(id);
+        HierarchyManager hierMgr = session.getHierarchyManager();
+        Name name;
+
+        if (!isShareable()) {
+            name = hierMgr.getName(id);
+        } else {
+            name = hierMgr.getName(getNodeId(), getParentId());
+        }
+        return name;
     }
 
     /**
@@ -2033,31 +2041,12 @@
             throw new ConstraintViolationException(msg);
         }
 
-        // (5) verify that source is shareable
-        if (!src.isShareable()) {
-            String msg = "Source node at " + src.safeGetJCRPath() + " is not shareable.";
-            log.debug(msg);
-            throw new RepositoryException(msg);
-        }
-
-        // (6) detect share cycle
-        NodeId srcId = src.getNodeId();
+        // (5) do clone operation
         NodeId parentId = getNodeId();
-        HierarchyManager hierMgr = session.getHierarchyManager();
-        if (parentId.equals(srcId) || hierMgr.isAncestor(srcId, parentId)) {
-            String msg = "This would create a share cycle.";
-            log.debug(msg);
-            throw new RepositoryException(msg);
-        }
-
-        // (7) do clone operation (modify and store affected states)
-        if (!src.addShare(parentId)) {
-            String msg = "Adding a shareable node twice to the same parent is not supported.";
-            log.debug(msg);
-            throw new UnsupportedRepositoryOperationException(msg);
-        }
+        src.addShare(parentId);
 
-        // (8) modify the state of 'this', i.e. the parent node
+        // (6) modify the state of 'this', i.e. the parent node
+        NodeId srcId = src.getNodeId();
         thisState = (NodeState) getOrCreateTransientItemState();
         // add new child node entry
         thisState.addChildNodeEntry(name, srcId);
@@ -3223,24 +3212,44 @@
     }
 
     /**
-     * Add a parent to the shared set. This method does not check whether
-     * adding this parent would create a share cycle (and should therefore
-     * strictly be used internally), it does, however detect whether the given
-     * parent is already contained in the shared set.
-     *
-     * @return <code>true</code> if adding succeeded;
-     *         <code>false</code> otherwise.
+     * Add a parent to the shared set. This method checks first, whether:
+     * <ul>
+     * <li>this node is shareable</li>
+     * <li>adding this parent would create a share cycle</li>
+     * <li>whether this parent is already contained in the shared set</li>
+     * </ul>
+     * @param parentId parent to add to the shared set
+     * @throws RepositoryException if an error occurs
      */
-    protected boolean addShare(NodeId parentId) throws RepositoryException {
-        // quickly verify whether the share is already contained before
-        // possibly changing the referenced state
+    protected void addShare(NodeId parentId) throws RepositoryException {
+        // verify that we're shareable
+        if (!isShareable()) {
+            String msg = "Node at " + safeGetJCRPath() + " is not shareable.";
+            log.debug(msg);
+            throw new RepositoryException(msg);
+        }
+
+        // detect share cycle
+        NodeId srcId = getNodeId();
+        HierarchyManager hierMgr = session.getHierarchyManager();
+        if (parentId.equals(srcId) || hierMgr.isAncestor(srcId, parentId)) {
+            String msg = "This would create a share cycle.";
+            log.debug(msg);
+            throw new RepositoryException(msg);
+        }
+
+        // quickly verify whether the share is already contained before creating
+        // a transient state in vain
         NodeState state = (NodeState) this.state;
-        if (state.containsShare(parentId)) {
-            return false;
+        if (!state.containsShare(parentId)) {
+            state = (NodeState) getOrCreateTransientItemState();
+            if (state.addShare(parentId)) {
+                return;
+            }
         }
-        // now make modifications
-        state = (NodeState) getOrCreateTransientItemState();
-        return state.addShare(parentId);
+        String msg = "Adding a shareable node twice to the same parent is not supported.";
+        log.debug(msg);
+        throw new UnsupportedRepositoryOperationException(msg);
     }
 
     /**
@@ -4327,6 +4336,9 @@
                         // check if one of this restoretrees node
                         if (removeExisting) {
                             existing.remove();
+                        } else if (existing.isShareable()) {
+                            // if existing node is shareable, then clone it
+                            restoredChild = clone(existing, f.getName());
                         } else {
                             // since we delete the OPV=Copy children beforehand, all
                             // found nodes must be outside of this tree
@@ -4337,8 +4349,10 @@
                         // ignore, item with uuid does not exist
                     }
                 }
-                restoredChild = addNode(f.getName(), f);
-                restoredChild.restoreFrozenState(f, vsel, restored, removeExisting);
+                if (restoredChild == null) {
+                    restoredChild = addNode(f.getName(), f);
+                    restoredChild.restoreFrozenState(f, vsel, restored, removeExisting);
+                }
 
             } else if (child instanceof InternalFrozenVersionHistory) {
                 InternalFrozenVersionHistory f = (InternalFrozenVersionHistory) child;

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ShareableNodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ShareableNodeTest.java?rev=645444&r1=645443&r2=645444&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ShareableNodeTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/ShareableNodeTest.java Mon Apr  7 03:22:47 2008
@@ -36,6 +36,7 @@
 import javax.jcr.observation.ObservationManager;
 import javax.jcr.query.Query;
 import javax.jcr.query.QueryResult;
+import javax.jcr.version.Version;
 
 import org.apache.jackrabbit.core.observation.SynchronousEventListener;
 import org.apache.jackrabbit.test.AbstractJCRTest;
@@ -48,7 +49,7 @@
     //------------------------------------------------------ specification tests
 
     /**
-     * Verifies that Node.getIndex returns the correct index in a shareable
+     * Verify that Node.getIndex returns the correct index in a shareable
      * node (6.13).
      */
     public void testGetIndex() throws Exception {
@@ -79,7 +80,7 @@
     }
 
     /**
-     * Verifies that Node.getName returns the correct name in a shareable node
+     * Verify that Node.getName returns the correct name in a shareable node
      * (6.13).
      */
     public void testGetName() throws Exception {
@@ -109,7 +110,7 @@
     }
 
     /**
-     * Verifies that Node.getPath returns the correct path in a shareable
+     * Verify that Node.getPath returns the correct path in a shareable
      * node (6.13).
      */
     public void testGetPath() throws Exception {
@@ -230,7 +231,7 @@
     }
 
     /**
-     * Checks new API Node.getSharedSet() (6.13.1)
+     * Check new API Node.getSharedSet() (6.13.1)
      */
     public void testGetSharedSet() throws Exception {
         // setup parent nodes and first child
@@ -254,7 +255,7 @@
     }
 
     /**
-     * Adds the mix:shareable mixin to a node (6.13.2).
+     * Add the mix:shareable mixin to a node (6.13.2).
      */
     public void testAddMixin() throws Exception {
         // setup parent node and first child
@@ -267,7 +268,51 @@
     }
 
     /**
-     * Checks new API Node.removeShare() (6.13.4).
+     * Create a shareable node by restoring it (6.13.3).
+     */
+    public void testRestore() throws Exception {
+        // setup parent nodes and first child
+        Node a1 = testRootNode.addNode("a1");
+        Node a2 = testRootNode.addNode("a2");
+        Node b1 = a1.addNode("b1");
+        testRootNode.save();
+
+        // make b1 shareable
+        b1.addMixin("mix:shareable");
+        b1.save();
+
+        // clone
+        Workspace workspace = b1.getSession().getWorkspace();
+        workspace.clone(workspace.getName(), b1.getPath(),
+                a2.getPath() + "/b2", false);
+
+        // make a2 versionable
+        a2.addMixin("mix:versionable");
+        a2.save();
+
+        // check in version and check out again
+        Version v = a2.checkin();
+        a2.checkout();
+
+        // delete b2 and save
+        a2.getNode("b2").remove();
+        a2.save();
+
+        // verify shareable set contains one element only
+        Node[] shared = getSharedSet(b1);
+        assertEquals(1, shared.length);
+
+        // restore version
+        a2.restore(v, false);
+
+        // verify shareable set contains two elements again
+        shared = getSharedSet(b1);
+        assertEquals(2, shared.length);
+    }
+
+
+    /**
+     * Check new API Node.removeShare() (6.13.4).
      */
     public void testRemoveShare() throws Exception {
         // setup parent nodes and first child
@@ -301,7 +346,7 @@
     }
 
     /**
-     * Checks new API Node.removeSharedSet() (6.13.4).
+     * Check new API Node.removeSharedSet() (6.13.4).
      */
     public void testRemoveSharedSet() throws Exception {
         // setup parent nodes and first child
@@ -329,7 +374,7 @@
     }
 
     /**
-     * Invokes Node.removeSharedSet(), but saves only one of the parent nodes
+     * Invoke Node.removeSharedSet(), but save only one of the parent nodes
      * of the shared set. This doesn't need to be supported according to the
      * specification (6.13.4).
      */
@@ -362,7 +407,7 @@
     }
 
     /**
-     * Verifies that shareable nodes in the same shared set have the same
+     * Verify that shareable nodes in the same shared set have the same
      * jcr:uuid (6.13.10).
      */
     public void testSameUUID() throws Exception {
@@ -485,6 +530,64 @@
     }
 
     /**
+     * Verify export and import of a tree containing multiple nodes in the
+     * same shared set (6.13.14). The first serialized node in that shared
+     * set is serialized in the normal fashion (with all of its properties
+     * and children), but any subsequent shared node in that shared set is
+     * serialized as a special node of type <code>nt:share</code>, which
+     * contains only the <code>jcr:uuid</code> property of the shared node
+     * and the <code>jcr:primaryType</code> property indicating the type
+     * <code>nt:share</code>.
+     */
+    public void testImportExportNtShare() throws Exception {
+        // setup parent nodes and first child
+        Node p = testRootNode.addNode("p");
+        Node a1 = p.addNode("a1");
+        Node a2 = p.addNode("a2");
+        Node b1 = a1.addNode("b1");
+        testRootNode.save();
+
+        // add mixin
+        b1.addMixin("mix:shareable");
+        b1.save();
+
+        // clone
+        Session session = b1.getSession();
+        Workspace workspace = session.getWorkspace();
+        workspace.clone(workspace.getName(), b1.getPath(),
+                a2.getPath() + "/b2", false);
+
+        // create temp file
+        File tmpFile = File.createTempFile("test", null);
+        tmpFile.deleteOnExit();
+
+        // export system view of /p
+        OutputStream out = new FileOutputStream(tmpFile);
+        try {
+            session.exportSystemView(p.getPath(), out, false, false);
+        } finally {
+            out.close();
+        }
+
+        // delete p and save
+        p.remove();
+        testRootNode.save();
+
+        // and import again underneath test root
+        InputStream in = new FileInputStream(tmpFile);
+        try {
+            workspace.importXML(testRootNode.getPath(), in,
+                    ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
+        } finally {
+            in.close();
+        }
+
+        // verify shared set consists of two nodes
+        Node[] shared = getSharedSet(testRootNode.getNode("p/a1/b1"));
+        assertEquals(2, shared.length);
+    }
+
+    /**
      * Verify system view import via workspace (6.13.14). Export a system view
      * containing a shareable node and verify, that reimporting underneath
      * a different parent adds another member to the shared set and does not
@@ -715,7 +818,7 @@
     }
 
     /**
-     * Verifies that observation events are sent only once (6.13.15).
+     * Verify that observation events are sent only once (6.13.15).
      */
     public void testObservation() throws Exception {
         // setup parent nodes and first child
@@ -803,7 +906,7 @@
     }
 
     /**
-     * Verifies that a lock applies to all nodes in a shared set (6.13.16).
+     * Verify that a lock applies to all nodes in a shared set (6.13.16).
      */
     public void testLock() throws Exception {
         // setup parent nodes and first child
@@ -850,7 +953,60 @@
     }
 
     /**
-     * Clones a mix:shareable node to the same workspace (6.13.20). Verifies
+     * Restore a shareable node and remove an existing shareable node (6.13.19)
+     * In this case the particular shared node is removed but its descendants
+     * continue to exist below the remaining members of the shared set.
+     */
+    public void testRestoreRemoveExisting() throws Exception {
+        // setup parent nodes and first child
+        Node a1 = testRootNode.addNode("a1");
+        Node a2 = testRootNode.addNode("a2");
+        Node b1 = a1.addNode("b1");
+        testRootNode.save();
+
+        // make b1 shareable
+        b1.addMixin("mix:shareable");
+        b1.save();
+
+        // clone
+        Workspace workspace = b1.getSession().getWorkspace();
+        workspace.clone(workspace.getName(), b1.getPath(),
+                a2.getPath() + "/b2", false);
+
+        // add child c
+        b1.addNode("c");
+        b1.save();
+
+        // make a2 versionable
+        a2.addMixin("mix:versionable");
+        a2.save();
+
+        // check in version and check out again
+        Version v = a2.checkin();
+        a2.checkout();
+
+        // delete b2 and save
+        a2.getNode("b2").remove();
+        a2.save();
+
+        // verify shareable set contains one elements only
+        Node[] shared = getSharedSet(b1);
+        assertEquals(1, shared.length);
+
+        // restore version and remove existing (i.e. b1)
+        a2.restore(v, true);
+
+        // verify shareable set contains still one element
+        shared = getSharedSet(a2.getNode("b2"));
+        assertEquals(1, shared.length);
+
+        // verify child c still exists
+        Node[] children = toArray(a2.getNode("b2").getNodes());
+        assertEquals(1, children.length);
+    }
+
+    /**
+     * Clone a mix:shareable node to the same workspace (6.13.20). Verify
      * that cloning without mix:shareable fails.
      */
     public void testClone() throws Exception {
@@ -882,10 +1038,12 @@
 
     /**
      * Clone a mix:shareable node to the same workspace multiple times, remove
-     * all parents and save.
+     * all parents and save. Exposes an error that occurred when having more
+     * than two members in a shared set and parents were removed in the same
+     * order they were created.
      */
     public void testCloneMultipleTimes() throws Exception {
-        int count = 10;
+        final int count = 10;
         Node[] parents = new Node[count];
 
         // setup parent nodes and first child
@@ -915,7 +1073,7 @@
     }
 
     /**
-     * Verifies that Node.isSame returns <code>true</code> for shareable nodes
+     * Verify that Node.isSame returns <code>true</code> for shareable nodes
      * in the same shared set (6.13.21)
      */
     public void testIsSame() throws Exception {
@@ -945,7 +1103,7 @@
     }
 
     /**
-     * Removes mix:shareable from a shareable node. This is unsupported in
+     * Remove mix:shareable from a shareable node. This is unsupported in
      * Jackrabbit (6.13.22).
      */
     public void testRemoveMixin() throws Exception {
@@ -969,7 +1127,7 @@
     }
 
     /**
-     * Verifies that a descendant of a shareable node appears once in the
+     * Verify that a descendant of a shareable node appears once in the
      * result set (6.13.23)
      */
     public void testSearch() throws Exception {
@@ -1009,7 +1167,7 @@
     //--------------------------------------------------------- limitation tests
 
     /**
-     * Clones a mix:shareable node to the same workspace, with the same
+     * Clone a mix:shareable node to the same workspace, with the same
      * parent. This is unsupported in Jackrabbit.
      */
     public void testCloneToSameParent() throws Exception {
@@ -1035,7 +1193,7 @@
     }
 
     /**
-     * Moves a node in a shared set. This is unsupported in Jackrabbit.
+     * Move a node in a shared set. This is unsupported in Jackrabbit.
      */
     public void testMoveShareableNode() throws Exception {
         // setup parent nodes and first childs
@@ -1061,7 +1219,7 @@
     }
 
     /**
-     * Transiently moves a node in a shared set. This is unsupported in
+     * Transiently move a node in a shared set. This is unsupported in
      * Jackrabbit.
      */
     public void testTransientMoveShareableNode() throws Exception {
@@ -1096,7 +1254,7 @@
      * @param n node
      * @return array of nodes in shared set
      */
-    private Node[] getSharedSet(Node n) throws RepositoryException {
+    private static Node[] getSharedSet(Node n) throws RepositoryException {
         return toArray(((NodeImpl) n).getSharedSet());
     }