Index: src/main/java/org/jboss/dna/graph/Graph.java =================================================================== --- src/main/java/org/jboss/dna/graph/Graph.java (revision 1044) +++ src/main/java/org/jboss/dna/graph/Graph.java (working copy) @@ -564,10 +564,11 @@ public Copy copy( Location from ) { return new CopyAction(this, from) { @Override - protected Graph submit( Locations from, + protected Graph submit( String fromWorkspaceName, + Locations from, Location into, Name childName ) { - String workspaceName = getCurrentWorkspaceName(); + String workspaceName = fromWorkspaceName != null ? fromWorkspaceName : getCurrentWorkspaceName(); do { requests.copyBranch(from.getLocation(), workspaceName, @@ -2368,10 +2369,11 @@ assertNotExecuted(); return new CopyAction(this.nextRequests, from) { @Override - protected BatchConjunction submit( Locations from, - Location into, - Name copyName ) { - String workspaceName = getCurrentWorkspaceName(); + protected BatchConjunction submit( String fromWorkspaceName, + Locations from, + Location into, + Name copyName ) { + String workspaceName = fromWorkspaceName != null ? fromWorkspaceName : getCurrentWorkspaceName(); do { requestQueue.copyBranch(from.getLocation(), workspaceName, into, workspaceName, copyName); } while ((from = from.next()) != null); @@ -3993,10 +3995,20 @@ * @param The interface that is to be returned when this request is completed * @author Randall Hauch */ - public interface Copy extends To, Into, And> { + public interface Copy extends FromWorkspace>, To, Into, And> { } /** + * The interface for specifying that a node should come from a workspace other than the current + * workspace. + * + * @param The interface that is to be returned when this request is completed + */ + public interface FromWorkspace { + Next fromWorkspace(String workspaceName); + } + + /** * The interface for defining additional properties on a new node. * * @param The interface that is to be returned when this create request is completed @@ -5759,11 +5771,66 @@ return submit(from, null, Location.create(createPath(before)), newName); } } + + protected abstract class IntoAction extends AbstractAction implements Into { + protected String fromWorkspaceName; + protected Locations from; + + protected IntoAction(T afterConjunction) { + super(afterConjunction); + } + protected IntoAction(T afterConjunction, String fromWorkspaceName, Locations from) { + super(afterConjunction); + + this.fromWorkspaceName = fromWorkspaceName; + this.from = from; + } + + /** + * Submit any requests to move the targets into the supplied parent location + * + * @param from the locations that are being copied + * @param into the parent location + * @param nameForCopy the name that should be used for the copy, or null if the name should be the same as the original + * @return this object, for method chaining + */ + protected abstract T submit( String fromWorkspaceName, + Locations from, + Location into, + Name nameForCopy ); + + public T into( Location into ) { + return submit(fromWorkspaceName, from, into, null); + } + + public T into( Path into ) { + return submit(fromWorkspaceName, from, Location.create(into), null); + } + + public T into( UUID into ) { + return submit(fromWorkspaceName, from, Location.create(into), null); + } + + public T into( Property firstIdProperty, + Property... additionalIdProperties ) { + return submit(fromWorkspaceName, from, Location.create(firstIdProperty, additionalIdProperties), null); + } + + public T into( Property into ) { + return submit(fromWorkspaceName, from, Location.create(into), null); + } + + public T into( String into ) { + return submit(fromWorkspaceName, from, Location.create(createPath(into)), null); + } + + + } + @NotThreadSafe - protected abstract class CopyAction extends AbstractAction implements Copy { - private final Locations from; - + protected abstract class CopyAction extends IntoAction implements Copy { + /*package*/CopyAction( T afterConjunction, Location from ) { super(afterConjunction); @@ -5806,43 +5873,6 @@ return this; } - /** - * Submit any requests to move the targets into the supplied parent location - * - * @param from the locations that are being copied - * @param into the parent location - * @param nameForCopy the name that should be used for the copy, or null if the name should be the same as the original - * @return this object, for method chaining - */ - protected abstract T submit( Locations from, - Location into, - Name nameForCopy ); - - public T into( Location into ) { - return submit(from, into, null); - } - - public T into( Path into ) { - return submit(from, Location.create(into), null); - } - - public T into( UUID into ) { - return submit(from, Location.create(into), null); - } - - public T into( Property firstIdProperty, - Property... additionalIdProperties ) { - return submit(from, Location.create(firstIdProperty, additionalIdProperties), null); - } - - public T into( Property into ) { - return submit(from, Location.create(into), null); - } - - public T into( String into ) { - return submit(from, Location.create(createPath(into)), null); - } - public T to( Location desiredLocation ) { if (!desiredLocation.hasPath()) { throw new IllegalArgumentException(GraphI18n.unableToCopyToLocationWithoutAPath.text(this.from, desiredLocation)); @@ -5852,7 +5882,7 @@ throw new IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from, desiredLocation)); } Path parent = desiredPath.getParent(); - return submit(from, Location.create(parent), desiredPath.getLastSegment().getName()); + return submit(fromWorkspaceName, from, Location.create(parent), desiredPath.getLastSegment().getName()); } public T to( Path desiredPath ) { @@ -5860,12 +5890,27 @@ throw new IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from, desiredPath)); } Path parent = desiredPath.getParent(); - return submit(from, Location.create(parent), desiredPath.getLastSegment().getName()); + return submit(fromWorkspaceName, from, Location.create(parent), desiredPath.getLastSegment().getName()); } public T to( String desiredPath ) { return to(createPath(desiredPath)); } + + public Into fromWorkspace(String workspaceName) { + final CopyAction source = this; + return new IntoAction(this.afterConjunction(), fromWorkspaceName, this.from) { + + @Override + protected T submit( String fromWorkspaceName, + Locations from, + Location into, + Name nameForCopy ) { + return source.submit(fromWorkspaceName, from, into, nameForCopy); + } + + }; + } } @NotThreadSafe Index: src/test/java/org/jboss/dna/graph/GraphTest.java =================================================================== --- src/test/java/org/jboss/dna/graph/GraphTest.java (revision 1044) +++ src/test/java/org/jboss/dna/graph/GraphTest.java (working copy) @@ -184,9 +184,16 @@ protected void assertNextRequestIsCopy( Location from, Location to ) { + assertNextRequestIsCopy(this.graph.getCurrentWorkspaceName(), from, to); + } + + protected void assertNextRequestIsCopy( String fromWorkspace, + Location from, + Location to ) { Request request = executedRequests.poll(); assertThat(request, is(instanceOf(CopyBranchRequest.class))); CopyBranchRequest copy = (CopyBranchRequest)request; + assertThat(copy.fromWorkspace(), is(fromWorkspace)); assertThat(copy.from(), is(from)); assertThat(copy.into(), is(to)); } @@ -377,6 +384,24 @@ } @Test + public void shouldCopyNodeFromOtherWorkspace() { + graph.copy(validPath).fromWorkspace("other").into(validIdProperty1, validIdProperty2); + assertThat(numberOfExecutions, is(1)); + assertNextRequestIsCopy(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2)); + assertNoMoreRequests(); + + graph.copy(validPathString).into(validIdProperty1, validIdProperty2); + assertThat(numberOfExecutions, is(1)); + assertNextRequestIsCopy(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2)); + assertNoMoreRequests(); + + graph.copy(validUuid).into(validPath); + assertThat(numberOfExecutions, is(1)); + assertNextRequestIsCopy(Location.create(validUuid), Location.create(validPath)); + assertNoMoreRequests(); + } + + @Test public void shouldDeleteNode() { graph.delete(validPath); assertThat(numberOfExecutions, is(1));