Index: modeshape-graph/src/main/java/org/modeshape/graph/session/GraphSession.java =================================================================== --- modeshape-graph/src/main/java/org/modeshape/graph/session/GraphSession.java (revision 2125) +++ modeshape-graph/src/main/java/org/modeshape/graph/session/GraphSession.java (working copy) @@ -1645,7 +1645,10 @@ public class GraphSession { Location actualLocation = persistentNode.getLocation(); if (!this.location.isSame(actualLocation)) { // The actual location is changed, so update it ... - this.originalLocation = this.location = actualLocation; + this.originalLocation = actualLocation; + // However, the location of the node needs to be a function of the parent node's location, + // which has already been loaded by this session ... + this.location = actualLocation.with(this.location.getPath()); // copy the ID props, if any } // Update the persistent information ... cache.nodeOperations.materialize(persistentNode, this); @@ -1655,7 +1658,10 @@ public class GraphSession { Location actualLocation = subgraph.getLocation(); if (!this.location.isSame(actualLocation)) { // The actual location is changed, so update it ... - this.originalLocation = this.location = actualLocation; + this.originalLocation = actualLocation; + // However, the location of the node needs to be a function of the parent node's location, + // which has already been loaded by this session ... + this.location = actualLocation.with(this.location.getPath()); // copy the ID props, if any } // Update the persistent information ... cache.nodeOperations.materialize(subgraph.getRoot(), this); Index: modeshape-jcr/src/main/java/org/modeshape/jcr/SessionCache.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/SessionCache.java (revision 2125) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/SessionCache.java (working copy) @@ -1408,7 +1408,7 @@ class SessionCache { // Update the location of the JcrNode object... Path newPath = existingChild.getPath(); - existingChild.getPayload().getJcrNode().setLocation(existingChild.getLocation().with(newPath)); + setNewLocation(existingChild, newPath); return existingChild; } catch (ValidationException e) { @@ -1420,6 +1420,22 @@ class SessionCache { } } + private void setNewLocation( Node node, + Path newPath ) { + AbstractJcrNode jcrNode = node.getPayload().getJcrNode(false); + if (jcrNode != null) { + // The JCR Node object has been cached, so update the location ... + node.getPayload().getJcrNode().setLocation(node.getLocation().with(newPath)); + + // Now update the location on the cached children of that moved node ... + for (Node child : node.getChildren()) { + if (!child.isLoaded()) continue; + Path newChildPath = pathFactory.create(newPath, child.getSegment()); + setNewLocation(child, newChildPath); + } + } + } + public void addMixin( JcrNodeType mixinCandidateType ) throws javax.jcr.ValueFormatException, RepositoryException { try { PropertyInfo existingMixinProperty = node.getProperty(JcrLexicon.MIXIN_TYPES); @@ -3091,6 +3107,10 @@ class SessionCache { return this.nodeDefinitionId; } + public AbstractJcrNode getJcrNode( boolean loadIfMissing ) { + return loadIfMissing ? getJcrNode() : jcrNode.get(); + } + /** * Get the JCR node instance. * Index: modeshape-jcr/src/test/java/org/modeshape/jcr/MoveTest.java new file mode 100644 =================================================================== --- /dev/null (revision 2125) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/MoveTest.java (working copy) @@ -0,0 +1,43 @@ +/* + * ModeShape (http://www.modeshape.org) + * See the COPYRIGHT.txt file distributed with this work for information + * regarding copyright ownership. Some portions may be licensed + * to Red Hat, Inc. under one or more contributor license agreements. + * See the AUTHORS.txt file in the distribution for a full listing of + * individual contributors. + * + * ModeShape is free software. Unless otherwise indicated, all code in ModeShape + * is licensed to you under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * ModeShape is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.modeshape.jcr; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import org.apache.jackrabbit.test.AbstractJCRTest; +import org.modeshape.common.FixFor; + +public class MoveTest extends AbstractJCRTest { + + @FixFor( "MODE-851" ) + public void testMoveNode() throws RepositoryException { + testRootNode.addNode("test1").addNode("content"); + // Test fails only with this save + superuser.save(); + Node node1 = testRootNode.getNode("test1"); + superuser.move(node1.getPath(), testRootNode.getPath() + "/test2"); + Node content = node1.getNode("content"); + assertEquals(node1.getPath() + "/content", content.getPath()); + } +}