Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 55504 invoked from network); 28 Mar 2008 11:29:25 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 28 Mar 2008 11:29:25 -0000 Received: (qmail 29579 invoked by uid 500); 28 Mar 2008 11:29:23 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 29547 invoked by uid 500); 28 Mar 2008 11:29:23 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 29531 invoked by uid 99); 28 Mar 2008 11:29:23 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 28 Mar 2008 04:29:23 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 28 Mar 2008 11:28:51 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id B253E1A9832; Fri, 28 Mar 2008 04:29:02 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r642204 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/BatchedItemOperations.java main/java/org/apache/jackrabbit/core/ItemImpl.java test/java/org/apache/jackrabbit/core/ShareableNodeTest.java Date: Fri, 28 Mar 2008 11:28:58 -0000 To: commits@jackrabbit.apache.org From: dpfister@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080328112902.B253E1A9832@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: dpfister Date: Fri Mar 28 04:28:50 2008 New Revision: 642204 URL: http://svn.apache.org/viewvc?rev=642204&view=rev Log: JCR-1104 - JSR 283 support - shareble nodes (work in progress) 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/ItemImpl.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=642204&r1=642203&r2=642204&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 Fri Mar 28 04:28:50 2008 @@ -1676,6 +1676,7 @@ EffectiveNodeType ent = getEffectiveNodeType(srcState); boolean referenceable = ent.includesNodeType(NameConstants.MIX_REFERENCEABLE); boolean versionable = ent.includesNodeType(NameConstants.MIX_VERSIONABLE); + boolean shareable = ent.includesNodeType(NameConstants.MIX_SHAREABLE); switch (flag) { case COPY: // always create new uuid @@ -1736,6 +1737,10 @@ // copy node state newState.setMixinTypeNames(srcState.getMixinTypeNames()); newState.setDefinitionId(srcState.getDefinitionId()); + if (shareable) { + // initialize shared set + newState.addShare(destParentId); + } // copy child nodes Iterator iter = srcState.getChildNodeEntries().iterator(); while (iter.hasNext()) { @@ -1753,6 +1758,32 @@ * * todo FIXME delegate to 'node type instance handler' */ + + /** + * If child is shareble and its UUID has already been remapped, + * then simply add a reference to the state with that remapped + * UUID instead of copying the whole subtree. + */ + if (srcChildState.isShareable()) { + UUID uuid = refTracker.getMappedUUID(srcChildState.getNodeId().getUUID()); + if (uuid != null) { + NodeId mappedId = new NodeId(uuid); + if (stateMgr.hasItemState(mappedId)) { + NodeState destState = (NodeState) stateMgr.getItemState(mappedId); + if (!destState.isShareable()) { + String msg = "Remapped child is not shareable."; + throw new ItemStateException(msg); + } + if (!destState.addShare(id)) { + String msg = "Unable to add share to node: " + id; + throw new ItemStateException(msg); + } + stateMgr.store(destState); + newState.addChildNodeEntry(entry.getName(), mappedId); + continue; + } + } + } // recursive copying of child node NodeState newChildState = copyNodeState(srcChildState, srcChildPath, Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java?rev=642204&r1=642203&r2=642204&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java Fri Mar 28 04:28:50 2008 @@ -1177,7 +1177,7 @@ NodeId newParentId = nodeState.getParentId(); if (oldParentId != null) { if (newParentId == null) { - // node has been removed, add old parent + // node has been removed, add old parents // to dependencies if (overlayedState.isShareable()) { dependentIDs.addAll(overlayedState.getSharedSet()); 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=642204&r1=642203&r2=642204&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 Fri Mar 28 04:28:50 2008 @@ -35,243 +35,232 @@ import org.apache.jackrabbit.test.AbstractJCRTest; /** - * Tests features available with shareable nodes. + * Tests features available with shareable nodes. */ public class ShareableNodeTest extends AbstractJCRTest { //------------------------------------------------------ specification tests - + /** - * Verifies that Node.getIndex returns the correct index in a shareable + * Verifies that Node.getIndex returns the correct index in a shareable * node (6.13). */ public void testGetIndex() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); a2.addNode("b"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - + // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b", true); - ArrayList list = new ArrayList(); - - NodeIterator iter = ((NodeImpl) b1).getSharedSet(); - while (iter.hasNext()) { - list.add(iter.nextNode()); - } - - assertEquals(list.size(), 2); - b1 = (Node) list.get(0); - Node b2 = (Node) list.get(1); - assertEquals(b1.getIndex(), 1); - assertEquals(b2.getIndex(), 2); + Node[] shared = getSharedSet(b1); + assertEquals(2, shared.length); + b1 = shared[0]; + Node b2 = shared[1]; + + // verify indices of nodes b1/b2 in shared set + assertEquals(1, b1.getIndex()); + assertEquals(2, b2.getIndex()); } - + /** * Verifies that Node.getName returns the correct name in a shareable node * (6.13). */ public void testGetName() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - + // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); - ArrayList list = new ArrayList(); + Node[] shared = getSharedSet(b1); + assertEquals(2, shared.length); + b1 = shared[0]; + Node b2 = shared[1]; - NodeIterator iter = ((NodeImpl) b1).getSharedSet(); - while (iter.hasNext()) { - list.add(iter.nextNode()); - } - - assertEquals(list.size(), 2); - b1 = (Node) list.get(0); - Node b2 = (Node) list.get(1); - assertEquals(b1.getName(), "b1"); - assertEquals(b2.getName(), "b2"); + // verify names of nodes b1/b2 in shared set + assertEquals("b1", b1.getName()); + assertEquals("b2", b2.getName()); } - + /** - * Verifies that Node.getPath returns the correct path in a shareable + * Verifies that Node.getPath returns the correct path in a shareable * node (6.13). */ public void testGetPath() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - + // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); - ArrayList list = new ArrayList(); + Node[] shared = getSharedSet(b1); + assertEquals(2, shared.length); + b1 = shared[0]; + Node b2 = shared[1]; - NodeIterator iter = ((NodeImpl) b1).getSharedSet(); - while (iter.hasNext()) { - list.add(iter.nextNode()); - } - - assertEquals(list.size(), 2); - b1 = (Node) list.get(0); - Node b2 = (Node) list.get(1); - assertEquals(b1.getPath(), "/testroot/a1/b1"); - assertEquals(b2.getPath(), "/testroot/a2/b2"); + // verify paths of nodes b1/b2 in shared set + assertEquals("/testroot/a1/b1", b1.getPath()); + assertEquals("/testroot/a2/b2", b2.getPath()); } /** * Checks new API Node.getSharedSet() (6.13.1) */ public void testIterateSharedSet() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - + // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); - - NodeIterator iter = ((NodeImpl) b1).getSharedSet(); - int items = 0; - while (iter.hasNext()) { - iter.nextNode(); - items++; - } - assertEquals(items, 2); + + // verify shared set contains 2 items + Node[] shared = getSharedSet(b1); + assertEquals(2, shared.length); } /** * Adds the mix:shareable mixin to a node (6.13.2). */ public void testAddMixin() throws Exception { - // setup parent node and first child + // setup parent node and first child Node a = testRootNode.addNode("a"); Node b = a.addNode("b"); testRootNode.save(); - + b.addMixin("mix:shareable"); b.save(); } - + /** * Checks new API Node.removeShare() (6.13.4). */ public void testRemoveShare() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - + // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); - ArrayList list = new ArrayList(); + Node[] shared = getSharedSet(b1); + assertEquals(2, shared.length); + b1 = shared[0]; + Node b2 = shared[1]; - NodeIterator iter = ((NodeImpl) b1).getSharedSet(); - while (iter.hasNext()) { - list.add(iter.nextNode()); - } - - assertEquals(list.size(), 2); - b1 = (Node) list.get(0); - Node b2 = (Node) list.get(1); - assertTrue(b1.isSame(b2)); - assertTrue(b2.isSame(b1)); - + // remove b1 from shared set ((NodeImpl) b1).removeShare(); a1.save(); + + // verify shared set of b2 contains only 1 item, namely b2 itself + shared = getSharedSet(b2); + assertEquals(1, shared.length); + assertTrue(shared[0].isSame(b2)); } /** * Checks new API Node.removeSharedSet() (6.13.4). */ public void testRemoveSharedSet() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - + // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); + // remove shared set ((NodeImpl) b1).removeSharedSet(); testRootNode.save(); + + // verify neither a1 nor a2 contain any more children + assertFalse(a1.hasNodes()); + assertFalse(a2.hasNodes()); } - + /** * Invokes Node.removeSharedSet(), but saves only one of the parent nodes * of the shared set. This doesn't need to be supported according to the * specification (6.13.4). */ public void testRemoveSharedSetSaveOneParentOnly() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - + // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); + // remove shared set ((NodeImpl) b1).removeSharedSet(); - + try { + // save only one of the parents, should fail a1.save(); fail("Removing a shared set requires saving all parents."); } catch (ConstraintViolationException e) { - // expected + // expected } } @@ -280,31 +269,27 @@ * jcr:uuid (6.13.10). */ public void testSameUUID() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - + // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); - ArrayList list = new ArrayList(); + Node[] shared = getSharedSet(b1); + assertEquals(2, shared.length); + b1 = shared[0]; + Node b2 = shared[1]; - NodeIterator iter = ((NodeImpl) b1).getSharedSet(); - while (iter.hasNext()) { - list.add(iter.nextNode()); - } - - assertEquals(list.size(), 2); - b1 = (Node) list.get(0); - Node b2 = (Node) list.get(1); + // verify nodes in a shared set have the same jcr:uuid assertTrue(b1.getUUID().equals(b2.getUUID())); } @@ -314,55 +299,87 @@ * one is (6.13.11). */ public void testAddChild() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - + // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); - ArrayList list = new ArrayList(); + Node[] shared = getSharedSet(b1); + assertEquals(2, shared.length); + b1 = shared[0]; + Node b2 = shared[1]; - NodeIterator iter = ((NodeImpl) b1).getSharedSet(); - while (iter.hasNext()) { - list.add(iter.nextNode()); - } - assertEquals(list.size(), 2); - b1 = (Node) list.get(0); - Node b2 = (Node) list.get(1); - + // add node to b1, verify b2 is modified as well and contains that child b1.addNode("c"); assertTrue(b2.isModified()); assertTrue(b2.hasNode("c")); b1.save(); } - + + /** + * Copy a subtree that contains shareable nodes. Verify that the nodes + * newly created are not in the shared set that existed before the copy, + * but if two nodes in the source of a copy are in the same shared set, then + * the two corresponding nodes in the destination of the copy must also be + * in the same shared set (6.13.12). + */ + public void testCopy() throws Exception { + // setup parent node and first child + Node s = testRootNode.addNode("s"); + Node a1 = s.addNode("a1"); + Node a2 = s.addNode("a2"); + Node b1 = a1.addNode("b1"); + testRootNode.save(); + + // add mixin + b1.addMixin("mix:shareable"); + b1.save(); + + // clone + Workspace workspace = b1.getSession().getWorkspace(); + workspace.clone(workspace.getName(), b1.getPath(), + a2.getPath() + "/b2", true); + + // copy source tree to destination + workspace.copy(s.getPath(), testRootNode.getPath() + "/d"); + + // verify source contains shared set with 2 entries + Node[] shared = getSharedSet(b1); + assertEquals(2, shared.length); + + // verify destination contains shared set with 2 entries + shared = getSharedSet(testRootNode.getNode("d/a1/b1")); + assertEquals(2, shared.length); + } + /** * Verify that a share cycle is detected (6.13.13). */ public void testShareCycle() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - - // clone underneath b1: this must fail + Workspace workspace = b1.getSession().getWorkspace(); - + try { - workspace.clone(workspace.getName(), b1.getPath(), + // clone underneath b1: this must fail + workspace.clone(workspace.getName(), b1.getPath(), b1.getPath() + "/c", true); fail("Cloning should create a share cycle."); } catch (RepositoryException e) { @@ -374,95 +391,101 @@ * Verifies that observation events are sent only once (6.13.15). */ public void testObservation() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); + // event listener that counts events received class EventCounter implements SynchronousEventListener { - + private int count; - + public void onEvent(EventIterator events) { while (events.hasNext()) { events.nextEvent(); count++; } } - + public int getEventCount() { return count; } - + public void resetCount() { count = 0; } }; - + EventCounter el = new EventCounter(); - ObservationManager om = superuser.getWorkspace().getObservationManager(); + ObservationManager om = superuser.getWorkspace().getObservationManager(); - om.addEventListener(el, Event.NODE_ADDED, testRootNode.getPath(), + // add node underneath shared set: verify it generates one event only + om.addEventListener(el, Event.NODE_ADDED, testRootNode.getPath(), true, null, null, false); b1.addNode("c"); b1.save(); superuser.getWorkspace().getObservationManager().removeEventListener(el); - assertEquals(el.getEventCount(), 1); - + assertEquals(1, el.getEventCount()); + + // remove node underneath shared set: verify it generates one event only el.resetCount(); - om.addEventListener(el, Event.NODE_REMOVED, testRootNode.getPath(), + om.addEventListener(el, Event.NODE_REMOVED, testRootNode.getPath(), true, null, null, false); b1.getNode("c").remove(); b1.save(); superuser.getWorkspace().getObservationManager().removeEventListener(el); - assertEquals(el.getEventCount(), 1); + assertEquals(1, el.getEventCount()); + // add property underneath shared set: verify it generates one event only el.resetCount(); - om.addEventListener(el, Event.PROPERTY_ADDED, testRootNode.getPath(), + om.addEventListener(el, Event.PROPERTY_ADDED, testRootNode.getPath(), true, null, null, false); b1.setProperty("c", "1"); b1.save(); superuser.getWorkspace().getObservationManager().removeEventListener(el); - assertEquals(el.getEventCount(), 1); + assertEquals(1, el.getEventCount()); + // modify property underneath shared set: verify it generates one event only el.resetCount(); - om.addEventListener(el, Event.PROPERTY_CHANGED, testRootNode.getPath(), + om.addEventListener(el, Event.PROPERTY_CHANGED, testRootNode.getPath(), true, null, null, false); b1.setProperty("c", "2"); b1.save(); superuser.getWorkspace().getObservationManager().removeEventListener(el); - assertEquals(el.getEventCount(), 1); + assertEquals(1, el.getEventCount()); + // remove property underneath shared set: verify it generates one event only el.resetCount(); - om.addEventListener(el, Event.PROPERTY_REMOVED, testRootNode.getPath(), + om.addEventListener(el, Event.PROPERTY_REMOVED, testRootNode.getPath(), true, null, null, false); b1.getProperty("c").remove(); b1.save(); superuser.getWorkspace().getObservationManager().removeEventListener(el); - assertEquals(el.getEventCount(), 1); + assertEquals(1, el.getEventCount()); } - + /** * Verifies 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 + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); a1.addMixin("mix:lockable"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.addMixin("mix:lockable"); @@ -471,114 +494,111 @@ // add child c Node c = b1.addNode("c"); b1.save(); - + // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); - - ArrayList list = new ArrayList(); - NodeIterator iter = ((NodeImpl) b1).getSharedSet(); - while (iter.hasNext()) { - list.add(iter.nextNode()); - } - - assertEquals(list.size(), 2); - b1 = (Node) list.get(0); - Node b2 = (Node) list.get(1); - + Node[] shared = getSharedSet(b1); + assertEquals(2, shared.length); + b1 = shared[0]; + Node b2 = shared[1]; + // lock shareable node -> all nodes in shared set are locked b1.lock(false, true); - assertTrue(b2.isLocked()); - b1.unlock(); - + try { + assertTrue(b2.isLocked()); + } finally { + b1.unlock(); + } + // deep-lock parent -> locks (common) child node a1.lock(true, true); - assertTrue(c.isLocked()); - a1.unlock(); + try { + assertTrue(c.isLocked()); + } finally { + a1.unlock(); + } } - + /** * Clones a mix:shareable node to the same workspace (6.13.20). Verifies * that cloning without mix:shareable fails. */ public void testClone() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - - // clone (1st attempt, without mix:shareable) + Workspace workspace = b1.getSession().getWorkspace(); + try { - workspace.clone(workspace.getName(), b1.getPath(), + // clone (1st attempt, without mix:shareable, should fail) + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); fail("Cloning a node into the same workspace should fail."); } catch (RepositoryException e) { // expected } - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - + // clone (2nd attempt, with mix:shareable) - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); } - + /** * Verifies that Node.isSame returns true for shareable nodes * in the same shared set (6.13.21) */ public void testIsSame() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - + // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); - ArrayList list = new ArrayList(); + Node[] shared = getSharedSet(b1); + assertEquals(2, shared.length); + b1 = shared[0]; + Node b2 = shared[1]; - NodeIterator iter = ((NodeImpl) b1).getSharedSet(); - while (iter.hasNext()) { - list.add(iter.nextNode()); - } - - assertEquals(list.size(), 2); - b1 = (Node) list.get(0); - Node b2 = (Node) list.get(1); + // verify b1 is same as b2 (and vice-versa) assertTrue(b1.isSame(b2)); assertTrue(b2.isSame(b1)); } - + /** * Removes mix:shareable from a shareable node. This is unsupported in * Jackrabbit (6.13.22). */ public void testRemoveMixin() throws Exception { - // setup parent node and first child + // setup parent node and first child Node a = testRootNode.addNode("a"); Node b = a.addNode("b"); testRootNode.save(); - + // add mixin b.addMixin("mix:shareable"); b.save(); - - // remove mixin + try { + // remove mixin b.removeMixin("mix:shareable"); b.save(); fail("Removing mix:shareable should fail."); @@ -592,26 +612,26 @@ * result set (6.13.23) */ public void testSearch() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b1 = a1.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); // clone Workspace workspace = b1.getSession().getWorkspace(); - workspace.clone(workspace.getName(), b1.getPath(), + workspace.clone(workspace.getName(), b1.getPath(), a2.getPath() + "/b2", true); - + // add new referenceable child Node c = b1.addNode("c"); c.addMixin(mixReferenceable); b1.save(); - + String sql = "SELECT * FROM nt:unstructured WHERE jcr:uuid = '"+c.getUUID()+"'"; QueryResult res = workspace.getQueryManager().createQuery(sql, Query.SQL).execute(); @@ -621,31 +641,31 @@ while (iter.hasNext()) { list.add(iter.nextNode()); } - assertEquals(list.size(), 1); - assertTrue(((NodeImpl) list.get(0)).isSame(c)); + assertEquals(1, list.size()); + assertTrue(((Node) list.get(0)).isSame(c)); } //--------------------------------------------------------- limitation tests - + /** * Clones a mix:shareable node to the same workspace, with the same * parent. This is unsupported in Jackrabbit. */ public void testCloneToSameParent() throws Exception { - // setup parent nodes and first child + // setup parent nodes and first child Node a = testRootNode.addNode("a"); Node b1 = a.addNode("b1"); testRootNode.save(); - + // add mixin b1.addMixin("mix:shareable"); b1.save(); - - // clone + Workspace workspace = b1.getSession().getWorkspace(); - + try { - workspace.clone(workspace.getName(), b1.getPath(), + // clone to same parent + workspace.clone(workspace.getName(), b1.getPath(), a.getPath() + "/b2", true); fail("Cloning inside same parent should fail."); } catch (UnsupportedRepositoryOperationException e) { @@ -657,12 +677,12 @@ * Moves a node in a shared set. This is unsupported in Jackrabbit. */ public void testMoveShareableNode() throws Exception { - // setup parent nodes and first childs + // setup parent nodes and first childs Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b = a1.addNode("b"); testRootNode.save(); - + // add mixin b.addMixin("mix:shareable"); b.save(); @@ -671,37 +691,60 @@ Workspace workspace = b.getSession().getWorkspace(); try { + // move shareable node workspace.move(b.getPath(), a2.getPath() + "/b"); fail("Moving a mix:shareable should fail."); } catch (UnsupportedRepositoryOperationException e) { // expected } } - + /** - * Transiently moves a node in a shared set. This is unsupported in + * Transiently moves a node in a shared set. This is unsupported in * Jackrabbit. */ public void testTransientMoveShareableNode() throws Exception { - // setup parent nodes and first childs + // setup parent nodes and first childs Node a1 = testRootNode.addNode("a1"); Node a2 = testRootNode.addNode("a2"); Node b = a1.addNode("b"); testRootNode.save(); - + // add mixin b.addMixin("mix:shareable"); b.save(); // move Session session = superuser; - + try { + // move shareable node session.move(b.getPath(), a2.getPath() + "/b"); session.save(); fail("Moving a mix:shareable should fail."); } catch (UnsupportedRepositoryOperationException e) { // expected } + } + + //---------------------------------------------------------- utility methods + + /** + * Return a shared set as an array of nodes. + * + * @param n node + * @return array of nodes in shared set + */ + private Node[] getSharedSet(Node n) throws RepositoryException { + ArrayList list = new ArrayList(); + + NodeIterator iter = ((NodeImpl) n).getSharedSet(); + while (iter.hasNext()) { + list.add(iter.nextNode()); + } + + Node[] result = new Node[list.size()]; + list.toArray(result); + return result; } }