CheckArg.isNotNull(srcWorkspace, "source workspace name");
CheckArg.isNotNull(srcAbsPath, "source path");
CheckArg.isNotNull(destAbsPath, "destination path");
if (!graph.getWorkspaces().contains(srcWorkspace)) {
throw new NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(graph.getSourceName(), this.name));
}
// Create the paths ...
PathFactory factory = context.getValueFactories().getPathFactory();
Path srcPath = null;
Path destPath = null;
try {
srcPath = factory.create(srcAbsPath);
} catch (ValueFormatException e) {
throw new PathNotFoundException(JcrI18n.invalidPathParameter.text(srcAbsPath, "srcAbsPath"), e);
}
try {
destPath = factory.create(destAbsPath);
} catch (ValueFormatException e) {
throw new PathNotFoundException(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(JcrI18n.pathCannotHaveSameNameSiblingIndex.text(destAbsPath));
}
try {
// Use the session to verify that the node location has a definition and is valid with the new cloned child.
// This also performs the check permission for reading the parent ...
Name newNodeName = destPath.getLastSegment().getName();
SessionCache cache = this.session.cache();
Node<JcrNodePayload, JcrPropertyPayload> parent = cache.findNode(null, destPath.getParent());
cache.findBestNodeDefinition(parent, newNodeName, parent.getPayload().getPrimaryTypeName());
if (removeExisting) {
// This will remove any existing nodes in this (the "target") workspace that have the same UUIDs
// as nodes that will be put into this workspace with the clone operation. Thus, any such
// existing nodes will be removed; but if they're mandatory they cannot be removed, resulting
// in a ConstraintViolationException. Therefore, we have to do a little homework here ...
Set<UUID> uuidsInCloneBranch = getUuidsInBranch(srcPath, srcWorkspace);
if (!uuidsInCloneBranch.isEmpty()) {
// See if any of these exist in the current workspace, and if so whether they can be removed ...
// This is NOT very efficient, since it may result in a batch read for each node ...
GraphSession<JcrNodePayload, JcrPropertyPayload> graphSession = cache.graphSession();
Node<JcrNodePayload, JcrPropertyPayload> node = null;
for (UUID uuid : uuidsInCloneBranch) {
Location location = Location.create(uuid);
try {
node = graphSession.findNodeWith(location);
} catch (org.jboss.dna.graph.property.PathNotFoundException e) {
// okay, it's not found in the current workspace, so nothing to check ...
continue;
}
// Get the node type that owns the child node definition ...
NodeDefinitionId childDefnId = node.getPayload().getDefinitionId();
JcrNodeType nodeType = nodeTypeManager().getNodeType(childDefnId.getNodeTypeName());
JcrNodeDefinition childDefn = nodeType.childNodeDefinition(childDefnId);
if (childDefn.isMandatory()) {
// We can't just remove a mandatory node... unless its parent will be removed too!
String path = node.getPath().getString(context.getNamespaceRegistry());
throw new ConstraintViolationException(JcrI18n.cannotRemoveNodeFromClone.text(path, uuid));
}
// Check whether the node has any local changes ...
if (node.isChanged(true)) {
// This session has changes on nodes that will be removed as a result of the clone ...
String path = node.getPath().getString(context.getNamespaceRegistry());
throw new RepositoryException(JcrI18n.cannotRemoveNodeFromCloneDueToChangesInSession.text(path, uuid));
}
}
}
}
// Now perform the clone, using the direct (non-session) method ...
cache.graphSession().immediateClone(srcPath, srcWorkspace, destPath, removeExisting, false);
} catch (ItemNotFoundException e) {
// The destination path was not found ...
throw new PathNotFoundException(e.getLocalizedMessage(), e);
} catch (org.jboss.dna.graph.property.PathNotFoundException e) {
throw new PathNotFoundException(e.getLocalizedMessage(), e);
} catch (UuidAlreadyExistsException e) {
throw new ItemExistsException(e.getLocalizedMessage(), e);
} catch (InvalidWorkspaceException e) {
throw new NoSuchWorkspaceException(e.getLocalizedMessage(), e);
} catch (RepositorySourceException e) {
throw new RepositoryException(e.getLocalizedMessage(), e);
} catch (AccessControlException ace) {
throw new AccessDeniedException(ace);
}