/* * 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.jcr2spi; import java.io.ByteArrayInputStream; import javax.jcr.Item; import javax.jcr.ItemExistsException; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.PathNotFoundException; import javax.jcr.Property; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.apache.jackrabbit.JcrConstants; import org.apache.jackrabbit.commons.JcrUtils; import org.apache.jackrabbit.test.NotExecutableException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * <code>MoveTest</code>... */ public class MoveTest extends AbstractMoveTest { private static Logger log = LoggerFactory.getLogger(MoveTest.class); @Override protected boolean isSessionMove() { return true; } public void testMoveRoot() throws RepositoryException { Node root = superuser.getRootNode(); try { doMove(root.getPath(), destinationPath); fail("Moving the root node must fail with RepositoryException."); } catch (RepositoryException e) { // OK } } public void testMoveBelowDescendant() throws RepositoryException { try { doMove(srcParentNode.getPath(), moveNode.getPath() + "/" + nodeName2); fail("Moving the ancestor node below descendant must fail with RepositoryException."); } catch (RepositoryException e) { // OK } } public void testMoveDestinationWithIndex() throws RepositoryException { try { doMove(moveNode.getPath(), destinationPath + "[1]"); fail("Moving to destination with index must fail with RepositoryException."); } catch (RepositoryException e) { // OK } } /** * Test if a moved node returns the specified destination path and by the * way test, if the moved node is still valid. */ public void testMovedNodeGetPath() throws RepositoryException, NotExecutableException { String oldPath = moveNode.getPath(); if (destParentNode.hasNode(nodeName2)) { throw new NotExecutableException("Move destination already contains a child node with name " + nodeName2); } //move the node doMove(oldPath, destinationPath); assertEquals("After successful move the moved node must return the destination path.", destinationPath, moveNode.getPath()); } /** * Same as {@link #testMovedNodeGetPath()}, but calls save prior to the * test. */ public void testMovedNodeGetPath2() throws RepositoryException, NotExecutableException { String oldPath = moveNode.getPath(); if (destParentNode.hasNode(nodeName2)) { throw new NotExecutableException("Move destination already contains a child node with name " + nodeName2); } //move the node doMove(oldPath, destParentNode.getPath() + "/" + nodeName2); superuser.save(); assertEquals("After successful move the moved node must return the destination path.", destinationPath, moveNode.getPath()); } /** * Test if a moved node is not accessible by its old path any more */ public void testAccessMovedNodeByOldPath() throws RepositoryException, NotExecutableException { NodeIterator it = srcParentNode.getNodes(moveNode.getName()); int cnt = 0; while (it.hasNext()) { it.nextNode(); cnt++; } if (cnt > 1) { throw new NotExecutableException("Move source parent has multiple child nodes with name " + moveNode.getName()); } String oldPath = moveNode.getPath(); //move the node doMove(oldPath, destinationPath); try { superuser.getItem(oldPath); fail("A moved node must not be accessible by its old path any more."); } catch (PathNotFoundException e) { // ok. } } /** * Same as {@link #testAccessMovedNodeByOldPath()} but calls save() prior to * the test. */ public void testAccessMovedNodeByOldPath2() throws RepositoryException, NotExecutableException { NodeIterator it = srcParentNode.getNodes(moveNode.getName()); int cnt = 0; while (it.hasNext()) { it.nextNode(); cnt++; } if (cnt > 1) { throw new NotExecutableException("Move source parent has multiple child nodes with name " + moveNode.getName()); } String oldPath = moveNode.getPath(); //move the node doMove(oldPath, destinationPath); superuser.save(); try { superuser.getItem(oldPath); fail("A moved node must not be accessible by its old path any more."); } catch (PathNotFoundException e) { // ok. } } /** * Test if the accessing the moved node from the session returns the same * Node object, than the Node which was moved before. * * @throws RepositoryException * @throws NotExecutableException */ public void testMovedNodeIsSame() throws RepositoryException, NotExecutableException { if (destParentNode.hasNode(nodeName2)) { throw new NotExecutableException(destParentNode + " already has child node " + ". Test cannot be preformed if SNS is present."); } String oldPath = moveNode.getPath(); String newPath = destParentNode.getPath() + "/" + nodeName2; //move the node doMove(oldPath, destinationPath); Item movedItem = superuser.getItem(newPath); assertTrue("Moved Node must be the same after the move.", movedItem.isSame(moveNode)); } /** * Same as {@link #testMovedNodeIsSame()}, but calls save() before executing * the comparison. * * @throws RepositoryException * @throws NotExecutableException */ public void testMovedNodeIsSame2() throws RepositoryException, NotExecutableException { if (destParentNode.hasNode(nodeName2)) { throw new NotExecutableException(destParentNode + " already has child node " + ". Test cannot be preformed if SNS is present."); } String oldPath = moveNode.getPath(); //move the node doMove(oldPath, destinationPath); superuser.save(); Item movedItem = superuser.getItem(destinationPath); assertTrue("Moved Node must be the same after the move.", movedItem.isSame(moveNode)); } /** * Test if after the move, <code>Node.getParent()</code> returns the * destination parent. * * @throws RepositoryException */ public void testMovedNodeParent() throws RepositoryException { //move the node doMove(moveNode.getPath(), destinationPath); assertTrue("Parent of moved node must be the destination parent node.", moveNode.getParent().isSame(destParentNode)); } /** * Same as {@link #testMovedNodeParent()}, but calls save before executing * the comparison. * * @throws RepositoryException */ public void testMovedNodeParent2() throws RepositoryException { //move the node doMove(moveNode.getPath(), destinationPath); superuser.save(); assertTrue("Parent of moved node must be the destination parent node.", moveNode.getParent().isSame(destParentNode)); } /** * Tries to move a node using <code>{@link javax.jcr.Session#move(String src, String dest)} * </code> to a location where a property already exists with same name. * <br/> * With JCR 1.0 this should throw an <code>{@link javax.jcr.ItemExistsException}</code>. * With JCR 2.0 the support for same-named property and node is optional and * the expected behaviour depends on the * {@link Repository#OPTION_NODE_AND_PROPERTY_WITH_SAME_NAME_SUPPORTED} descriptor. */ public void testMovePropertyExists() throws RepositoryException, NotExecutableException { // try to create a property with the name of the node to be moved // to the destination parent Property destProperty; try { destProperty = destParentNode.setProperty(nodeName2, "anyString"); } catch (RepositoryException e) { throw new NotExecutableException("Cannot create property with name '" +nodeName2+ "' and value 'anyString' at move destination."); } // TODO: fix 2.0 behaviour according to the OPTION_NODE_AND_PROPERTY_WITH_SAME_NAME_SUPPORTED descriptor if ("1.0".equals(getHelper().getRepository().getDescriptor(Repository.SPEC_VERSION_DESC))) { try { // move the node doMove(moveNode.getPath(), destProperty.getPath()); fail("Moving a node to a location where a property exists must throw ItemExistsException"); } catch (ItemExistsException e) { // ok, works as expected } } else { // move the node: same name property and node must be supported // see Issue 725 doMove(moveNode.getPath(), destProperty.getPath()); } } /** * Regression tests for JCR-2528 * @throws RepositoryException */ public void testMoveReferenceableNode() throws RepositoryException { moveNode.addMixin(JcrConstants.MIX_REFERENCEABLE); moveNode.getSession().save(); superuser.move(moveNode.getPath(), destParentNode.getPath() + "/" + moveNode.getName()); superuser.save(); destParentNode.remove(); // JCR-2528 caused this call to throw a javax.jcr.InvalidItemStateException: Item has already // been removed by someone else. Status = REMOVED destParentNode.getSession().save(); } public void testMoveFile() throws RepositoryException, NotExecutableException { // create a new file String parentPath; String filePath; try { Node parent = testRootNode.addNode("parent"); Node n = JcrUtils.putFile(parent, "file", "text/plain", new ByteArrayInputStream("data".getBytes())); parentPath = parent.getPath(); filePath = n.getPath(); superuser.save(); } catch (RepositoryException e) { throw new NotExecutableException(); } Session s = getHelper().getSuperuserSession(); try { Node n1 = s.getNode(filePath); Node n2 = n1.getNode("jcr:content"); n2.setProperty("jcr:data", new java.io.ByteArrayInputStream("data2".getBytes())); n2.save(); String destPath = parentPath + "1"; if (isSessionMove()) { s.move(parentPath, destPath); s.save(); } else { s.getWorkspace().move(parentPath, destPath); } Node n3 = s.getNode(destPath + "/file"); Node n4 = n3.getNode("jcr:content"); n4.refresh(false); // call must succeed (see JCR-2472) Node n5 = n3.getNode("jcr:content"); } finally { s.logout(); } } }