Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java (revision 938) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java (working copy) @@ -60,6 +60,7 @@ import org.jboss.dna.jcr.JcrContentHandler.EnclosingSAXException; import org.jboss.dna.jcr.JcrContentHandler.SaveMode; import org.jboss.dna.jcr.JcrRepository.Option; +import org.jboss.dna.jcr.cache.NodeInfo; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -284,8 +285,28 @@ throw new RepositoryException(JcrI18n.invalidPathParameter.text(destAbsPath, "destAbsPath"), e); } + // Doing a literal test here because the path factory will canonicalize "/node[1]" to "/node" + if (destAbsPath.endsWith("]")) { + throw new RepositoryException(); + } + + /* + * Make sure that the node has a definition at the new location + */ + SessionCache cache = this.session.cache(); + NodeInfo nodeInfo = cache.findNodeInfo(null, srcPath); + NodeInfo parent = cache.findNodeInfo(null, destPath.getParent()); + + // This throws a ConstraintViolationException if there is no matching definition + cache.findBestNodeDefinition(parent.getUuid(), srcPath.getLastSegment().getName(), nodeInfo.getPrimaryTypeName()); + // Perform the copy operation, but use the "to" form (not the "into", which takes the parent) ... graph.copy(srcPath).to(destPath); + + /* + * In case the parent of the new destination has already been loaded, we need to purge it + */ + cache.purgeCachedNode(parent.getUuid()); } /** Index: dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java (revision 938) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java (working copy) @@ -234,6 +234,18 @@ } /** + * Purges the {@code NodeInfo} with the given {@code uuid} from the {@code cachedNodes} map only. This method + * does not modify any additional caches and should be called only when a workspace operation modifies some attribute of + * a node's children, requiring the session to reload the list of children from persistent storage. + * @param uuid the UUID of the node to clear from the cache + * @return whether info for this UUID existed in the cache + * @see JcrWorkspace#copy(String, String) + */ + boolean purgeCachedNode(UUID uuid) { + return this.cachedNodes.remove(uuid) != null; + } + + /** * Refreshes (removes the cached state) for all cached nodes. *

* If {@code keepChanges == true}, modified nodes will not have their state refreshed. @@ -514,7 +526,8 @@ List mixinTypeNames = node.getMixinTypeNames(); Children children = nodeInfo.getChildren(); - int snsCount = children.getCountOfSameNameSiblingsWithName(newNodeName); + // Need to add 1 to the existing count to simulate having the new node as a sibling + int snsCount = children.getCountOfSameNameSiblingsWithName(newNodeName) + 1; JcrNodeDefinition definition = nodeTypes().findChildNodeDefinition(primaryTypeName, mixinTypeNames, newNodeName, Index: dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java =================================================================== --- dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java (revision 938) +++ dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java (working copy) @@ -70,8 +70,11 @@ import org.apache.jackrabbit.test.api.WorkspaceCopyBetweenWorkspacesSameNameSibsTest; import org.apache.jackrabbit.test.api.WorkspaceCopyBetweenWorkspacesTest; import org.apache.jackrabbit.test.api.WorkspaceCopyBetweenWorkspacesVersionableTest; +import org.apache.jackrabbit.test.api.WorkspaceCopyReferenceableTest; +import org.apache.jackrabbit.test.api.WorkspaceCopySameNameSibsTest; import org.apache.jackrabbit.test.api.WorkspaceCopyVersionableTest; import org.apache.jackrabbit.test.api.WorkspaceMoveReferenceableTest; +import org.apache.jackrabbit.test.api.WorkspaceMoveSameNameSibsTest; import org.apache.jackrabbit.test.api.WorkspaceMoveVersionableTest; /** @@ -218,13 +221,13 @@ addTestSuite(WorkspaceCopyBetweenWorkspacesSameNameSibsTest.class); addTestSuite(WorkspaceCopyBetweenWorkspacesTest.class); addTestSuite(WorkspaceCopyBetweenWorkspacesVersionableTest.class); - // addTestSuite(WorkspaceCopyReferenceableTest.class); - // addTestSuite(WorkspaceCopySameNameSibsTest.class); - // addTestSuite(WorkspaceCopyTest.class); + addTestSuite(WorkspaceCopyReferenceableTest.class); + addTestSuite(WorkspaceCopySameNameSibsTest.class); + //addTestSuite(WorkspaceCopyTest.class); addTestSuite(WorkspaceCopyVersionableTest.class); addTestSuite(WorkspaceMoveReferenceableTest.class); - // addTestSuite(WorkspaceMoveSameNameSibsTest.class); - // addTestSuite(WorkspaceMoveTest.class); + addTestSuite(WorkspaceMoveSameNameSibsTest.class); + //addTestSuite(WorkspaceMoveTest.class); addTestSuite(WorkspaceMoveVersionableTest.class); addTestSuite(RepositoryLoginTest.class);