Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java (revision 844) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrSession.java (working copy) @@ -702,7 +706,7 @@ throw new ItemExistsException(); } - newParentNode.editor().moveToBeChild(sourceNode.nodeUuid, newNodeName.getName()); + newParentNode.editor().moveToBeChild(sourceNode, newNodeName.getName()); } /** Index: dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java (revision 844) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java (working copy) @@ -911,7 +1231,7 @@ * Move the child specified by the supplied UUID to be a child of this node, appending the child to the end of the current * list of children. This method automatically disconnects the node from its current parent. * - * @param nodeUuid the UUID of the existing node; may not be null + * @param child the UUID of the existing node; may not be null * @param newNodeName * @return the representation of the newly-added child, which includes the {@link ChildNode#getSnsIndex() * same-name-sibling index} @@ -920,9 +1240,10 @@ * @throws ConstraintViolationException if moving the node into this node violates this node's definition * @throws RepositoryException if any other error occurs while reading information from the repository */ - public ChildNode moveToBeChild( UUID nodeUuid, Name newNodeName ) + public ChildNode moveToBeChild( AbstractJcrNode child, Name newNodeName ) throws ItemNotFoundException, InvalidItemStateException, ConstraintViolationException, RepositoryException { + UUID nodeUuid = child.nodeUuid; if (nodeUuid.equals(node.getUuid()) || isAncestor(nodeUuid)) { Path pathOfNode = getPathFor(nodeUuid); Path thisPath = currentLocation.getPath(); @@ -930,29 +1251,17 @@ throw new RepositoryException(msg); } + boolean nameDoesNotChange = newNodeName == null || newNodeName.equals(child.path().getLastSegment()); + // Is the node already a child? - ChildNode child = node.getChildren().getChild(nodeUuid); - if (child != null) return child; + ChildNode existingChild = node.getChildren().getChild(nodeUuid); + if (existingChild != null && nameDoesNotChange) return existingChild; + JcrNodeDefinition definition = findBestNodeDefinition(node.getUuid(), newNodeName, null); + // Get an editor for the child (in its current location) and one for its parent ... - NodeEditor existingNodeEditor = getEditorFor(nodeUuid); - ChangedNodeInfo existingNodeInfo = existingNodeEditor.node; - UUID existingParent = existingNodeInfo.getParent(); - NodeEditor existingParentEditor = getEditorFor(existingParent); - ChangedNodeInfo existingParentInfo = existingParentEditor.node; + NodeEditor newChildEditor = getEditorFor(nodeUuid); - // Verify that this node's definition allows the specified child ... - Name childName = existingParentInfo.getChildren().getChild(nodeUuid).getName(); - int numSns = node.getChildren().getCountOfSameNameSiblingsWithName(childName); - JcrNodeDefinition definition = nodeTypes().findChildNodeDefinition(node.getPrimaryTypeName(), - node.getMixinTypeNames(), - childName, - childName, - numSns, - true); - if (definition == null) { - throw new ConstraintViolationException(); - } if (!definition.getId().equals(node.getDefinitionId())) { // The node definition changed, so try to set the property ... try { @@ -967,27 +1276,90 @@ node.setDefinitionId(definition.getId()); // And remove the property from the info ... - existingNodeEditor.removeProperty(DnaLexicon.NODE_DEFINITON); + newChildEditor.removeProperty(DnaLexicon.NODE_DEFINITON); } } // Remove the node from the current parent and add it to this ... - child = existingParentInfo.removeChild(nodeUuid, pathFactory); - ChildNode newChild = node.addChild(newNodeName, child.getUuid(), pathFactory); + ChangedNodeInfo newChildInfo = newChildEditor.node; + UUID existingParent = newChildInfo.getParent(); + ChangedNodeInfo existingParentInfo = getEditorFor(existingParent).node; + existingChild = existingParentInfo.removeChild(nodeUuid, pathFactory); + ChildNode newChild = node.addChild(newNodeName, existingChild.getUuid(), pathFactory); + // Set the child's changed representation to point to this node as its parent ... - existingNodeInfo.setParent(node.getUuid()); + newChildInfo.setParent(node.getUuid()); // Set up the peer relationship between the two nodes that must be saved together node.addPeer(existingParent); existingParentInfo.addPeer(node.getUuid()); + // Set up the peer relationship between the two nodes that must be saved together + node.addPeer(existingParent); + existingParentInfo.addPeer(node.getUuid()); + // Now, record the operation to do this ... - operations.move(existingNodeEditor.currentLocation).into(currentLocation); + if (nameDoesNotChange) { + operations.move(newChildEditor.currentLocation).into(currentLocation); + } + else { + operations.move(newChildEditor.currentLocation).as(newNodeName).into(currentLocation); + } return newChild; } Index: dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java =================================================================== --- dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java (revision 844) +++ dna-jcr/src/test/java/org/jboss/dna/jcr/JcrSessionTest.java (working copy) @@ -30,6 +30,7 @@ import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.stub; import java.io.ByteArrayInputStream; @@ -46,6 +47,7 @@ import javax.jcr.Item; import javax.jcr.NamespaceException; import javax.jcr.Node; +import javax.jcr.PathNotFoundException; import javax.jcr.Property; import javax.jcr.PropertyType; import javax.jcr.Repository; @@ -509,4 +511,18 @@ node.getUUID(); } + @Test + public void shouldMoveToNewName() throws Exception { + session.move("/a/b/c", "/a/b/d"); + + session.getRootNode().getNode("a").getNode("b").getNode("d"); + try { + session.getRootNode().getNode("a").getNode("b").getNode("c"); + + fail("Node still exists at /a/b/c after move"); + } + catch (PathNotFoundException e) { + // Expected + } + } }