throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException,
RepositoryException {
checkLive();
// Find the source path and destination path and check for permissions
Path srcPath = absolutePathFor(srcAbsPath);
checkPermission(srcPath, ModeShapePermissions.REMOVE);
Path destPath = absolutePathFor(destAbsPath);
checkPermission(destPath.getParent(), ModeShapePermissions.ADD_NODE);
if (srcPath.isRoot()) {
throw new RepositoryException(JcrI18n.unableToMoveRootNode.text(workspaceName()));
}
if (destPath.isRoot()) {
throw new RepositoryException(JcrI18n.rootNodeCannotBeDestinationOfMovedNode.text(workspaceName()));
}
if (!destPath.isIdentifier() && destAbsPath.endsWith("]")) {
// Doing a literal test here because the path factory will canonicalize "/node[1]" to "/node"
throw new RepositoryException(JcrI18n.pathCannotHaveSameNameSiblingIndex.text(destAbsPath));
}
if (srcPath.isAncestorOf(destPath)) {
String msg = JcrI18n.unableToMoveNodeToBeChildOfDecendent.text(srcAbsPath, destAbsPath, workspaceName());
throw new RepositoryException(msg);
}
if (srcPath.equals(destPath)) {
// Nothing to do ...
return;
}
// Get the node at the source path and the parent node of the destination path ...
AbstractJcrNode srcNode = node(srcPath);
AbstractJcrNode destParentNode = node(destPath.getParent());
SessionCache sessionCache = cache();
// Check whether these nodes are locked ...
if (srcNode.isLocked() && !srcNode.getLock().isLockOwningSession()) {
javax.jcr.lock.Lock sourceLock = srcNode.getLock();
if (sourceLock != null && sourceLock.getLockToken() == null) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(srcAbsPath));
}
}
if (destParentNode.isLocked() && !destParentNode.getLock().isLockOwningSession()) {
javax.jcr.lock.Lock newParentLock = destParentNode.getLock();
if (newParentLock != null && newParentLock.getLockToken() == null) {
throw new LockException(JcrI18n.lockTokenNotHeld.text(destAbsPath));
}
}
// Check whether the nodes that will be modified are checked out ...
AbstractJcrNode srcParent = srcNode.getParent();
if (!srcParent.isCheckedOut()) {
throw new VersionException(JcrI18n.nodeIsCheckedIn.text(srcNode.getPath()));
}
if (!destParentNode.isCheckedOut()) {
throw new VersionException(JcrI18n.nodeIsCheckedIn.text(destParentNode.getPath()));
}
// Check whether external nodes are involved
validateMoveForExternalNodes(srcPath, destPath);
// check whether the parent definition allows children which match the source
final Name newChildName = destPath.getLastSegment().getName();
destParentNode.validateChildNodeDefinition(newChildName, srcNode.getPrimaryTypeName(), true);
// We already checked whether the supplied destination path is below the supplied source path, but this isn't
// sufficient if any of the ancestors are shared nodes. Therefore, check whether the destination node
// is actually underneath the source node by walking up the destination path to see if there are any
// shared nodes (including the shareable node) below the source path ...
AbstractJcrNode destAncestor = destParentNode;
while (!destAncestor.isRoot()) {
if (destAncestor.isShareable()) {
SharedSet sharedSet = destAncestor.sharedSet();
AbstractJcrNode sharedNodeThatCreatesCircularity = sharedSet.getSharedNodeAtOrBelow(srcPath);
if (sharedNodeThatCreatesCircularity != null) {
Path badPath = sharedNodeThatCreatesCircularity.path();
throw new RepositoryException(JcrI18n.unableToMoveNodeDueToCycle.text(srcAbsPath, destAbsPath,
readable(badPath)));
}
}
destAncestor = destAncestor.getParent();