Author: bcarothers
Date: 2009-06-02 15:30:41 -0400 (Tue, 02 Jun 2009)
New Revision: 955
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ForkRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/request/MoveBranchRequestTest.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableNodeInfo.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java
Log:
DNA-376 Add request to change the order of a child node (or nodes) relative to the other
children
Applied DNA-376_final.patch which:
- Adds "before" property to MoveBranchRequest which can be used in lieu of the
"into" property. If the before is populated, the node should moved into the
parent of the "before" location and located immediately before the child node
with the "before" location. Added test case to WriteableConnectorTest to test
this behavior.
- Modified writable connectors to support "before" property on MoveBranchRequest
and no longer require that "into" property is not null.
- Added support for "before" preposition on Graph and Graph.Batch for move
operation.
- Modified JCR layer to support ordering of child nodes with AbstractJcrNode.orderBefore
by adding a method to SessionCache.NodeEditor and adding comparable operations to
ImmutableChildren and ChangedChildren
- Uncommented relevant tests in JcrTckTest
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-05-29 21:22:01 UTC
(rev 954)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-06-02 19:30:41 UTC
(rev 955)
@@ -437,10 +437,11 @@
@Override
protected Conjunction<Graph> submit( Locations from,
Location into,
+ Location before,
Name newName ) {
String workspaceName = getCurrentWorkspaceName();
do {
- requests.moveBranch(from.getLocation(), into, workspaceName,
newName);
+ requests.moveBranch(from.getLocation(), into, before, workspaceName,
newName);
} while ((from = from.next()) != null);
return and();
}
@@ -2204,10 +2205,11 @@
@Override
protected BatchConjunction submit( Locations from,
Location into,
+ Location before,
Name newName ) {
String workspaceName = getCurrentWorkspaceName();
do {
- requestQueue.moveBranch(from.getLocation(), into, workspaceName,
newName);
+ requestQueue.moveBranch(from.getLocation(), into, before,
workspaceName, newName);
} while ((from = from.next()) != null);
return and();
}
@@ -3712,6 +3714,86 @@
}
/**
+ * A component that defines the location before which a node should be copied or
moved. This is similar to an
+ * {@link Into}, but it allows for placing a node at a particular location within the
new destination, rather than
+ * always placing the moved or copied node as the last child of the new parent.
+ *
+ * @param <Next> The interface that is to be returned when this request is
completed
+ * @author Randall Hauch
+ */
+ public interface Before<Next> {
+ /**
+ * Finish the request by specifying the location of the node before which the
node should be copied/moved. This operation
+ * will result in the copied/moved node having the same name as the original (but
with the appropriately-determined
+ * same-name-sibling index). If you want to control the name of the node for the
newly copied/moved node, use
+ * {@link To#to(Location)} instead.
+ *
+ * @param parentLocation the location of the new parent
+ * @return the interface for additional requests or actions
+ * @see To#to(Location)
+ */
+ Next before( Location parentLocation );
+
+ /**
+ * Finish the request by specifying the location of the node before which the
node should be copied/moved. This operation
+ * will result in the copied/moved node having the same name as the original (but
with the appropriately-determined
+ * same-name-sibling index). If you want to control the name of the node for the
newly copied/moved node, use
+ * {@link To#to(String)} instead.
+ *
+ * @param parentPath the path of the new parent
+ * @return the interface for additional requests or actions
+ * @see To#to(String)
+ */
+ Next before( String parentPath );
+
+ /**
+ * Finish the request by specifying the location of the node before which the
node should be copied/moved. This operation
+ * will result in the copied/moved node having the same name as the original (but
with the appropriately-determined
+ * same-name-sibling index). If you want to control the name of the node for the
newly copied/moved node, use
+ * {@link To#to(Path)} instead.
+ *
+ * @param parentPath the path of the new parent
+ * @return the interface for additional requests or actions
+ * @see To#to(Path)
+ */
+ Next before( Path parentPath );
+
+ /**
+ * Finish the request by specifying the location of the node before which the
node should be copied/moved. This operation
+ * will result in the copied/moved node having the same name as the original (but
with the appropriately-determined
+ * same-name-sibling index).
+ *
+ * @param parentUuid the UUID of the new parent
+ * @return the interface for additional requests or actions
+ */
+ Next before( UUID parentUuid );
+
+ /**
+ * Finish the request by specifying the location of the node before which the
node should be copied/moved. This operation
+ * will result in the copied/moved node having the same name as the original (but
with the appropriately-determined
+ * same-name-sibling index).
+ *
+ * @param parentIdProperty the property that uniquely identifies the new parent
+ * @return the interface for additional requests or actions
+ */
+ Next before( Property parentIdProperty );
+
+ /**
+ * Finish the request by specifying the location of the node before which the
node should be copied/moved. This operation
+ * will result in the copied/moved node having the same name as the original (but
with the appropriately-determined
+ * same-name-sibling index).
+ *
+ * @param firstParentIdProperty the first property that, with the
<code>additionalIdProperties</code>, uniquely identifies
+ * the new parent
+ * @param additionalParentIdProperties the additional properties that, with the
<code>additionalIdProperties</code>,
+ * uniquely identifies the new parent
+ * @return the interface for additional requests or actions
+ */
+ Next before( Property firstParentIdProperty,
+ Property... additionalParentIdProperties );
+ }
+
+ /**
* A component that defines the location to which a node should be copied or moved.
*
* @param <Next> The interface that is to be returned when this request is
completed
@@ -3850,7 +3932,7 @@
* @param <Next> The interface that is to be returned when this request is
completed
* @author Randall Hauch
*/
- public interface Move<Next> extends AsName<Into<Next>>,
Into<Next>, And<Move<Next>> {
+ public interface Move<Next> extends AsName<Into<Next>>,
Into<Next>, Before<Next>, And<Move<Next>> {
}
/**
@@ -5508,15 +5590,31 @@
*
* @param from the location(s) that are being moved; never null
* @param into the parent location
+ * @param before the location of the child of the parent before which this node
should be placed
* @param newName the new name for the node being moved; may be null
* @return this object, for method chaining
*/
protected abstract T submit( Locations from,
Location into,
+ Location before,
Name newName );
+ /**
+ * Submit any requests to move the targets into the supplied parent location
+ *
+ * @param from the location(s) that are being moved; never null
+ * @param into the parent location
+ * @param newName the new name for the node being moved; may be null
+ * @return this object, for method chaining
+ */
+ protected T submit( Locations from,
+ Location into,
+ Name newName ) {
+ return submit(from, into, null, newName);
+ }
+
public T into( Location into ) {
- return submit(from, into, newName);
+ return submit(from, into, null, newName);
}
public T into( Path into ) {
@@ -5539,6 +5637,31 @@
public T into( String into ) {
return submit(from, Location.create(createPath(into)), newName);
}
+
+ public T before( Location before ) {
+ return submit(from, null, before, newName);
+ }
+
+ public T before( Path before ) {
+ return submit(from, null, Location.create(before), newName);
+ }
+
+ public T before( UUID before ) {
+ return submit(from, null, Location.create(before), newName);
+ }
+
+ public T before( Property firstIdProperty,
+ Property... additionalIdProperties ) {
+ return submit(from, null, Location.create(firstIdProperty,
additionalIdProperties), newName);
+ }
+
+ public T before( Property before ) {
+ return submit(from, null, Location.create(before), newName);
+ }
+
+ public T before( String before ) {
+ return submit(from, null, Location.create(createPath(before)), newName);
+ }
}
@NotThreadSafe
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ForkRequestProcessor.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ForkRequestProcessor.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ForkRequestProcessor.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -1129,6 +1129,7 @@
if (projectedFromNode == null) return;
ProjectedNode projectedIntoNode = project(request.into(), request.inWorkspace(),
request, true);
if (projectedIntoNode == null) return;
+ ProjectedNode projectedBeforeNode = request.before() != null ?
project(request.before(), request.inWorkspace(), request, true) : null;
// Limitation: only able to project the move if the 'from' and
'into' are in the same source & projection ...
while (projectedFromNode != null) {
@@ -1160,11 +1161,12 @@
ProxyNode fromProxy = projectedFromNode.asProxy();
ProxyNode intoProxy = projectedIntoNode.asProxy();
+ ProxyNode beforeProxy = request.before() != null ? projectedBeforeNode.asProxy()
: null;
assert
fromProxy.projection().getSourceName().equals(intoProxy.projection().getSourceName());
boolean sameLocation = fromProxy.isSameLocationAsOriginal() &&
intoProxy.isSameLocationAsOriginal();
// Create the pushed-down request ...
- MoveBranchRequest pushDown = new MoveBranchRequest(fromProxy.location(),
intoProxy.location(), intoProxy.workspaceName(),
+ MoveBranchRequest pushDown = new MoveBranchRequest(fromProxy.location(),
intoProxy.location(), beforeProxy.location(), intoProxy.workspaceName(),
request.desiredName(),
request.conflictBehavior());
// Create the federated request ...
FederatedRequest federatedRequest = new FederatedRequest(request);
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -351,21 +351,23 @@
* @param desiredNewName the new name for the node, if it is to be changed; may
be null
* @param newWorkspace the workspace containing the new parent node
* @param newParent the new parent; may not be the {@link Workspace#getRoot()
root}
+ * @param beforeNode the node before which this new node should be placed
*/
public void moveNode( ExecutionContext context,
InMemoryNode node,
Name desiredNewName,
Workspace newWorkspace,
- InMemoryNode newParent ) {
+ InMemoryNode newParent,
+ InMemoryNode beforeNode) {
assert context != null;
assert newParent != null;
assert node != null;
- assert newWorkspace.getRoot().equals(newParent) != true;
+// Why was this restriction here? -- BRC
+// assert newWorkspace.getRoot().equals(newParent) != true;
assert this.getRoot().equals(node) != true;
InMemoryNode oldParent = node.getParent();
Name oldName = node.getName().getName();
if (oldParent != null) {
- if (oldParent.equals(newParent)) return;
boolean removed = oldParent.getChildren().remove(node);
assert removed == true;
node.setParent(null);
@@ -377,9 +379,16 @@
newName = desiredNewName;
node.setName(context.getValueFactories().getPathFactory().createSegment(desiredNewName,
1));
}
- newParent.getChildren().add(node);
+
+ if (beforeNode == null) {
+ newParent.getChildren().add(node);
+ }
+ else {
+ int index = newParent.getChildren().indexOf(beforeNode);
+ newParent.getChildren().add(index, node);
+ }
correctSameNameSiblingIndexes(context, newParent, newName);
-
+
// If the node was moved to a new workspace...
if (!this.equals(newWorkspace)) {
// We need to remove the node from this workspace's map of nodes ...
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -217,16 +217,35 @@
InMemoryRepository.Workspace workspace = getWorkspace(request,
request.inWorkspace());
if (workspace == null) return;
+ InMemoryNode beforeNode = request.before() != null ? getTargetNode(workspace,
request, request.before()) : null;
InMemoryNode node = getTargetNode(workspace, request, request.from());
if (node == null) return;
// Look up the new parent, which must exist ...
- Path newParentPath = request.into().getPath();
+ Path newParentPath;
+
+ if (request.into() != null) {
+ newParentPath = request.into().getPath();
+ }
+ else {
+ // into or before cannot both be null
+ assert beforeNode != null;
+
+ // Build the path from the before node to the root.
+ LinkedList<Path.Segment> segments = new
LinkedList<Path.Segment>();
+ InMemoryNode current = beforeNode.getParent();
+ while (current != workspace.getRoot()) {
+ segments.addFirst(current.getName());
+ current = current.getParent();
+ }
+ newParentPath =
getExecutionContext().getValueFactories().getPathFactory().createAbsolutePath(segments);
+ }
+
InMemoryNode newParent = workspace.getNode(newParentPath);
- workspace.moveNode(getExecutionContext(), node, request.desiredName(), workspace,
newParent);
+ workspace.moveNode(getExecutionContext(), node, request.desiredName(), workspace,
newParent, beforeNode);
assert node.getParent() == newParent;
Path newPath =
getExecutionContext().getValueFactories().getPathFactory().create(newParentPath,
node.getName());
Location oldLocation = getActualLocation(request.from().getPath(), node);
- Location newLocation = Location.create(newPath, newParent.getUuid());
+ Location newLocation = Location.create(newPath, node.getUuid());
request.setActualLocations(oldLocation, newLocation);
recordChange(request);
}
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -627,7 +627,7 @@
Location into,
String workspaceName,
Name newNameForNode ) {
- return add(new MoveBranchRequest(from, into, workspaceName, newNameForNode,
MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
+ return add(new MoveBranchRequest(from, into, null, workspaceName, newNameForNode,
MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
}
/**
@@ -635,7 +635,26 @@
*
* @param from the location of the top node in the existing branch that is to be
moved
* @param into the location of the existing node into which the branch should be
moved
+ * @param before the location of the node before which the branch should be moved;
may be null
* @param workspaceName the name of the workspace
+ * @param newNameForNode the new name for the node being moved, or null if the name
of the original should be used
+ * @return this builder for method chaining; never null
+ * @throws IllegalArgumentException if any of the parameters are null
+ */
+ public BatchRequestBuilder moveBranch( Location from,
+ Location into,
+ Location before,
+ String workspaceName,
+ Name newNameForNode ) {
+ return add(new MoveBranchRequest(from, into, before, workspaceName,
newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
+ }
+
+ /**
+ * Create a request to move a branch from one location into another.
+ *
+ * @param from the location of the top node in the existing branch that is to be
moved
+ * @param into the location of the existing node into which the branch should be
moved
+ * @param workspaceName the name of the workspace
* @param conflictBehavior the expected behavior if an equivalently-named child
already exists at the <code>into</code>
* location
* @return this builder for method chaining; never null
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/MoveBranchRequest.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -44,6 +44,7 @@
private final Location from;
private final Location into;
+ private final Location before;
private final String workspaceName;
private final Name desiredNameForNode;
private final NodeConflictBehavior conflictBehavior;
@@ -61,7 +62,7 @@
public MoveBranchRequest( Location from,
Location into,
String workspaceName ) {
- this(from, into, workspaceName, null, DEFAULT_CONFLICT_BEHAVIOR);
+ this(from, into, null, workspaceName, null, DEFAULT_CONFLICT_BEHAVIOR);
}
/**
@@ -77,7 +78,7 @@
Location into,
String workspaceName,
Name newNameForMovedNode ) {
- this(from, into, workspaceName, newNameForMovedNode, DEFAULT_CONFLICT_BEHAVIOR);
+ this(from, into, null, workspaceName, newNameForMovedNode,
DEFAULT_CONFLICT_BEHAVIOR);
}
/**
@@ -94,7 +95,7 @@
Location into,
String workspaceName,
NodeConflictBehavior conflictBehavior ) {
- this(from, into, workspaceName, null, conflictBehavior);
+ this(from, into, null, workspaceName, null, conflictBehavior);
}
/**
@@ -102,6 +103,8 @@
*
* @param from the location of the top node in the existing branch that is to be
moved
* @param into the location of the existing node into which the branch should be
moved
+ * @param before the location of the child of the {@code into} node that the branch
should be placed before; null indicates
+ * that the branch should be the last child of its new parent
* @param workspaceName the name of the workspace
* @param newNameForMovedNode the new name for the node being moved, or null if the
name of the original should be used
* @param conflictBehavior the expected behavior if an equivalently-named child
already exists at the <code>into</code>
@@ -110,15 +113,17 @@
*/
public MoveBranchRequest( Location from,
Location into,
+ Location before,
String workspaceName,
Name newNameForMovedNode,
NodeConflictBehavior conflictBehavior ) {
CheckArg.isNotNull(from, "from");
- CheckArg.isNotNull(into, "into");
+ // CheckArg.isNotNull(into, "into");
CheckArg.isNotNull(workspaceName, "workspaceName");
CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
this.from = from;
this.into = into;
+ this.before = before;
this.workspaceName = workspaceName;
this.desiredNameForNode = newNameForMovedNode;
this.conflictBehavior = conflictBehavior;
@@ -143,6 +148,15 @@
}
/**
+ * Get the location defining the node before which the branch is to be placed
+ *
+ * @return the to location; null indicates that the branch should be the last child
node of its new parent
+ */
+ public Location before() {
+ return before;
+ }
+
+ /**
* Get the name of the workspace in which the branch exists.
*
* @return the name of the workspace containing the branch; never null
@@ -197,9 +211,10 @@
* @return true if this move request really doesn't change the parent of the
node, or false if it cannot be determined
*/
public boolean hasNoEffect() {
- if (into.hasPath() && into.hasIdProperties() == false &&
from.hasPath()) {
+ if (into != null && into.hasPath() && into.hasIdProperties() ==
false && from.hasPath()) {
if (!from.getPath().getParent().equals(into.getPath())) return false;
if (desiredName() != null &&
!desiredName().equals(from.getPath().getLastSegment().getName())) return false;
+ if (before != null) return false;
return true;
}
// Can't be determined for certain
@@ -232,7 +247,7 @@
if (!newLocation.hasPath()) {
throw new
IllegalArgumentException(GraphI18n.actualNewLocationMustHavePath.text(newLocation));
}
- if (into().hasPath() &&
!newLocation.getPath().getParent().isSameAs(into.getPath())) {
+ if (into() != null && into().hasPath() &&
!newLocation.getPath().getParent().isSameAs(into.getPath())) {
throw new
IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(newLocation,
into));
}
Name actualNewName = newLocation.getPath().getLastSegment().getName();
@@ -270,8 +285,16 @@
@Override
public boolean changes( String workspace,
Path path ) {
+ if (this.into() != null) {
+ return this.workspaceName.equals(workspace)
+ && (into.hasPath() && into.getPath().isAtOrBelow(path)
|| from.hasPath() && from.getPath().isAtOrBelow(path));
+ }
+ // into or before must be non-null
+ assert before() != null;
return this.workspaceName.equals(workspace)
- && (into.hasPath() && into.getPath().isAtOrBelow(path) ||
from.hasPath() && from.getPath().isAtOrBelow(path));
+ && (before.hasPath() &&
before.getPath().getParent().isAtOrBelow(path) || from.hasPath()
+
&& from.getPath().isAtOrBelow(path));
+
}
/**
@@ -281,7 +304,7 @@
*/
@Override
public Location changedLocation() {
- return into;
+ return into != null ? into : before;
}
/**
@@ -343,9 +366,10 @@
@Override
public String toString() {
if (desiredName() != null) {
- return "move branch " + from() + " in the \"" +
inWorkspace() + "\" workspace into " + into() + " with name "
- + desiredName();
+ return "move branch " + from() + " in the \"" +
inWorkspace() + "\" workspace "
+ + (into() == null ? "before " + before() : "into "
+ into()) + " with name " + desiredName();
}
- return "move branch " + from() + " in the \"" +
inWorkspace() + "\" workspace into " + into();
+ return "move branch " + from() + " in the \"" +
inWorkspace() + "\" workspace into "
+ + (into() == null ? "before " + before() : "into " +
into());
}
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -474,9 +474,28 @@
Location into,
String workspaceName,
Name newNameForNode ) {
- return process(new MoveBranchRequest(from, into, workspaceName, newNameForNode,
MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
+ return process(new MoveBranchRequest(from, into, null, workspaceName,
newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
}
+
/**
+ * Create a request to move a branch from one location into another before the given
child node of the new location.
+ *
+ * @param from the location of the top node in the existing branch that is to be
moved
+ * @param into the location of the existing node into which the branch should be
moved
+ * @param before the location of the node before which the branch should be moved;
may be null
+ * @param workspaceName the name of the workspace
+ * @param newNameForNode the new name for the node being moved, or null if the name
of the original should be used
+ * @return the request; never null
+ * @throws IllegalArgumentException if any of the parameters are null
+ */
+ public MoveBranchRequest moveBranch( Location from,
+ Location into,
+ Location before,
+ String workspaceName,
+ Name newNameForNode ) {
+ return process(new MoveBranchRequest(from, into, before, workspaceName,
newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
+ }
+ /**
* Create a request to move a branch from one location into another.
*
* @param from the location of the top node in the existing branch that is to be
moved
@@ -494,7 +513,7 @@
Name newNameForNode,
NodeConflictBehavior conflictBehavior ) {
if (conflictBehavior == null) conflictBehavior =
MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR;
- return process(new MoveBranchRequest(from, into, workspaceName, newNameForNode,
conflictBehavior));
+ return process(new MoveBranchRequest(from, into, null, workspaceName,
newNameForNode, conflictBehavior));
}
/**
Modified:
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java
===================================================================
---
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepositoryWorkspaceTest.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -241,7 +241,7 @@
assertThat(workspace.getNode(pathFactory.create("/d/e")),
is(sameInstance(node_e)));
assertThat(workspace.getNode(pathFactory.create("/d/b")),
is(sameInstance(node_b2)));
- workspace.moveNode(context, node_b, null, workspace, node_d);
+ workspace.moveNode(context, node_b, null, workspace, node_d, null);
assertThat(workspace.getNode(pathFactory.create("/")),
is(sameInstance(workspace.getRoot())));
assertThat(workspace.getNode(pathFactory.create("/a")),
is(sameInstance(node_a)));
@@ -251,7 +251,7 @@
assertThat(workspace.getNode(pathFactory.create("/d/b[2]")),
is(sameInstance(node_b)));
assertThat(workspace.getNode(pathFactory.create("/d/b[2]/c")),
is(sameInstance(node_c)));
- workspace.moveNode(context, node_b, null, workspace, node_e);
+ workspace.moveNode(context, node_b, null, workspace, node_e, null);
assertThat(workspace.getNode(pathFactory.create("/")),
is(sameInstance(workspace.getRoot())));
assertThat(workspace.getNode(pathFactory.create("/a")),
is(sameInstance(node_a)));
@@ -263,6 +263,55 @@
}
@Test
+ public void shouldMoveNodeBeforeAnother() {
+ InMemoryNode root = workspace.getRoot();
+ InMemoryNode node_a = workspace.createNode(context, root,
nameFactory.create("a"), null);
+ InMemoryNode node_b = workspace.createNode(context, node_a,
nameFactory.create("b"), null);
+ InMemoryNode node_c = workspace.createNode(context, node_b,
nameFactory.create("c"), null);
+ InMemoryNode node_d = workspace.createNode(context, root,
nameFactory.create("d"), null);
+ InMemoryNode node_e = workspace.createNode(context, node_d,
nameFactory.create("e"), null);
+ InMemoryNode node_b2 = workspace.createNode(context, node_d,
nameFactory.create("b"), null);
+ Name propName = nameFactory.create("prop");
+ node_b.setProperty(propertyFactory.create(propName, "node_b"));
+ node_b2.setProperty(propertyFactory.create(propName, "node_b2"));
+
+ assertThat(workspace.getNodesByUuid().size(), is(7));
+ assertThat(workspace.getNode(pathFactory.create("/")),
is(sameInstance(workspace.getRoot())));
+ assertThat(workspace.getNode(pathFactory.create("/a")),
is(sameInstance(node_a)));
+ assertThat(workspace.getNode(pathFactory.create("/a/b")),
is(sameInstance(node_b)));
+ assertThat(workspace.getNode(pathFactory.create("/a/b/c")),
is(sameInstance(node_c)));
+ assertThat(workspace.getNode(pathFactory.create("/d")),
is(sameInstance(node_d)));
+ assertThat(workspace.getNode(pathFactory.create("/d/e")),
is(sameInstance(node_e)));
+ assertThat(workspace.getNode(pathFactory.create("/d/b")),
is(sameInstance(node_b2)));
+
assertThat(workspace.getNode(pathFactory.create("/a/b")).getProperty(propName).getFirstValue().toString(),
is("node_b"));
+
assertThat(workspace.getNode(pathFactory.create("/d/b")).getProperty(propName).getFirstValue().toString(),
is("node_b2"));
+
+ // Move before a node with the same name
+ workspace.moveNode(context, node_b, null, workspace, node_d, node_b2);
+
+ assertThat(workspace.getNode(pathFactory.create("/")),
is(sameInstance(workspace.getRoot())));
+ assertThat(workspace.getNode(pathFactory.create("/a")),
is(sameInstance(node_a)));
+ assertThat(workspace.getNode(pathFactory.create("/d")),
is(sameInstance(node_d)));
+ assertThat(workspace.getNode(pathFactory.create("/d/e")),
is(sameInstance(node_e)));
+ assertThat(workspace.getNode(pathFactory.create("/d/b[2]")),
is(sameInstance(node_b2)));
+ assertThat(workspace.getNode(pathFactory.create("/d/b[1]")),
is(sameInstance(node_b)));
+ assertThat(workspace.getNode(pathFactory.create("/d/b[1]/c")),
is(sameInstance(node_c)));
+
assertThat(workspace.getNode(pathFactory.create("/d/b[1]")).getProperty(propName).getFirstValue().toString(),
is("node_b"));
+
assertThat(workspace.getNode(pathFactory.create("/d/b[2]")).getProperty(propName).getFirstValue().toString(),
is("node_b2"));
+
+ // Move after the last node
+ workspace.moveNode(context, node_b, null, workspace, root, null);
+
+ assertThat(workspace.getNode(pathFactory.create("/")),
is(sameInstance(workspace.getRoot())));
+ assertThat(workspace.getNode(pathFactory.create("/a")),
is(sameInstance(node_a)));
+ assertThat(workspace.getNode(pathFactory.create("/d")),
is(sameInstance(node_d)));
+ assertThat(workspace.getNode(pathFactory.create("/d/e")),
is(sameInstance(node_e)));
+ assertThat(workspace.getNode(pathFactory.create("/b")),
is(sameInstance(node_b)));
+ assertThat(workspace.getNode(pathFactory.create("/b/c")),
is(sameInstance(node_c)));
+ assertThat(workspace.getNode(pathFactory.create("/d/b")),
is(sameInstance(node_b2)));
+ }
+
+ @Test
public void shouldMoveNodesFromOneWorkspaceToAnother() {
// Populate the workspace with some content ...
InMemoryNode root = workspace.getRoot();
@@ -304,7 +353,7 @@
assertThat(new_workspace.getNode(pathFactory.create("/d/b")),
is(sameInstance(new_node_b2)));
// Move 'workspace::/a/b' into 'newWorkspace::/d'
- workspace.moveNode(context, node_b, null, new_workspace, new_node_d);
+ workspace.moveNode(context, node_b, null, new_workspace, new_node_d, null);
assertThat(workspace.getNodesByUuid().size(), is(5));
assertThat(workspace.getNode(pathFactory.create("/")),
is(sameInstance(workspace.getRoot())));
Modified:
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java
===================================================================
---
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -1386,4 +1386,184 @@
"The quick
brown fox jumped over the moon. What? "));
}
+ @Test
+ public void shouldMoveAndRenameNodesToNameWithSameNameSibling() {
+ // Create the tree (at total of 40 nodes, plus the extra 6 added later)...
+ // /
+ // /node1
+ // /node1/node1
+ // /node1/node1/node1
+ // /node1/node1/node2
+ // /node1/node1/node3
+ // /node1/node2
+ // /node1/node2/node1
+ // /node1/node2/node2
+ // /node1/node2/node3
+ // /node1/node3
+ // /node1/node3/node1
+ // /node1/node3/node2
+ // /node1/node3/node3
+ // /node2
+ // /node2/node1
+ // /node2/node1/node1
+ // /node2/node1/node2
+ // /node2/node1/node3
+ // /node2/node2
+ // /node2/node2/node1
+ // /node2/node2/node2
+ // /node2/node2/node3
+ // /node2/node3
+ // /node2/node3/node1
+ // /node2/node3/node2
+ // /node2/node3/node3
+ // /node3
+ // /node3/node1
+ // /node3/node1/node1
+ // /node3/node1/node2
+ // /node3/node1/node3
+ // /node3/node2
+ // /node3/node2/node1
+ // /node3/node2/node2
+ // /node3/node2/node3
+ // /node3/node3
+ // /node3/node3/node1
+ // /node3/node3/node2
+ // /node3/node3/node3
+ // /secondBranch1
+ // /secondBranch1/secondBranch1
+ // /secondBranch1/secondBranch2
+ // /secondBranch2
+ // /secondBranch2/secondBranch1
+ // /secondBranch2/secondBranch2
+
+ String initialPath = "";
+ int depth = 3;
+ int numChildrenPerNode = 3;
+ int numPropertiesPerNode = 3;
+ Stopwatch sw = new Stopwatch();
+ boolean batch = true;
+ createSubgraph(graph, initialPath, depth, numChildrenPerNode,
numPropertiesPerNode, batch, sw, System.out, null);
+
+ // Delete two branches ...
+ graph.move("/node2").before("/node3/node2");
+
+ // Now assert the structure ...
+ assertThat(graph.getChildren().of("/"),
hasChildren(segment("node1"), segment("node3")));
+ assertThat(graph.getChildren().of("/node1"),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node1"),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node2"),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node3"),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(graph.getChildren().of("/node1/node3/node1"),
hasChildren());
+
+ assertThat(graph.getChildren().of("/node3"),
hasChildren(segment("node1"),
+
segment("node2[1]"),
+
segment("node3"),
+
segment("node2[2]")));
+ assertThat(graph.getChildren().of("/node3/node2[1]"),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3"),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node3/node1"),
hasChildren());
+ assertThat(graph.getChildren().of("/node3/node2[1]"),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node2[1]/node1"),
+ hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node2[1]/node2"),
+ hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node2[1]/node3"),
+ hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(graph.getChildren().of("/node3/node2[1]/node1/node1"),
hasChildren());
+
+ Subgraph subgraph = graph.getSubgraphOfDepth(4).at("/node3");
+ assertThat(subgraph, is(notNullValue()));
+ assertThat(subgraph.getNode(".").getChildren(),
hasChildren(segment("node2"), segment("node3")));
+ assertThat(subgraph.getNode("."), hasProperty("property1",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property2",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("."), hasProperty("property3",
"The quick brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[2]").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(subgraph.getNode("node2[2]"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[2]"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[2]"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3").getChildren(), isEmpty());
+ assertThat(subgraph.getNode("node3"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node3"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(subgraph.getNode("node2[1]"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]/node1").getChildren(),
hasChildren(segment("node1"),
+
segment("node2"),
+
segment("node3")));
+ assertThat(subgraph.getNode("node2[1]/node1"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]/node1"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]/node1"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]/node1/node1").getChildren(),
isEmpty());
+ assertThat(subgraph.getNode("node2[1]/node1/node1"),
hasProperty("property1",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node1/node1"),
hasProperty("property2",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node1/node1"),
hasProperty("property3",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node1/node2").getChildren(),
isEmpty());
+ assertThat(subgraph.getNode("node2[1]/node1/node2"),
hasProperty("property1",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node1/node2"),
hasProperty("property2",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node1/node2"),
hasProperty("property3",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node1/node3").getChildren(),
isEmpty());
+ assertThat(subgraph.getNode("node2[1]/node1/node3"),
hasProperty("property1",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node1/node3"),
hasProperty("property2",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node1/node3"),
hasProperty("property3",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node2"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]/node2"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]/node2"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]/node2/node1").getChildren(),
isEmpty());
+ assertThat(subgraph.getNode("node2[1]/node2/node1"),
hasProperty("property1",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node2/node1"),
hasProperty("property2",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node2/node1"),
hasProperty("property3",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node2/node2").getChildren(),
isEmpty());
+ assertThat(subgraph.getNode("node2[1]/node2/node2"),
hasProperty("property1",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node2/node2"),
hasProperty("property2",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node2/node2"),
hasProperty("property3",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node2/node3").getChildren(),
isEmpty());
+ assertThat(subgraph.getNode("node2[1]/node2/node3"),
hasProperty("property1",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node2/node3"),
hasProperty("property2",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node2/node3"),
hasProperty("property3",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node3"),
hasProperty("property1", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]/node3"),
hasProperty("property2", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]/node3"),
hasProperty("property3", "The quick brown fox jumped over the moon. What?
"));
+ assertThat(subgraph.getNode("node2[1]/node3/node1").getChildren(),
isEmpty());
+ assertThat(subgraph.getNode("node2[1]/node3/node1"),
hasProperty("property1",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node3/node1"),
hasProperty("property2",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node3/node1"),
hasProperty("property3",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node3/node2").getChildren(),
isEmpty());
+ assertThat(subgraph.getNode("node2[1]/node3/node2"),
hasProperty("property1",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node3/node2"),
hasProperty("property2",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node3/node2"),
hasProperty("property3",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node3/node3").getChildren(),
isEmpty());
+ assertThat(subgraph.getNode("node2[1]/node3/node3"),
hasProperty("property1",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node3/node3"),
hasProperty("property2",
+ "The quick
brown fox jumped over the moon. What? "));
+ assertThat(subgraph.getNode("node2[1]/node3/node3"),
hasProperty("property3",
+ "The quick
brown fox jumped over the moon. What? "));
+ }
+
}
Modified:
trunk/dna-graph/src/test/java/org/jboss/dna/graph/request/MoveBranchRequestTest.java
===================================================================
---
trunk/dna-graph/src/test/java/org/jboss/dna/graph/request/MoveBranchRequestTest.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/dna-graph/src/test/java/org/jboss/dna/graph/request/MoveBranchRequestTest.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -27,6 +27,9 @@
import static org.hamcrest.core.IsNull.nullValue;
import static org.hamcrest.core.IsSame.sameInstance;
import static org.junit.Assert.assertThat;
+import org.jboss.dna.graph.NodeConflictBehavior;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.basic.BasicName;
import org.junit.Before;
import org.junit.Test;
@@ -53,8 +56,8 @@
new MoveBranchRequest(null, validPathLocation2, workspace2);
}
- @Test( expected = IllegalArgumentException.class )
- public void shouldNotAllowCreatingRequestWithNullToLocation() {
+ @Test
+ public void shouldAllowCreatingRequestWithNullToLocation() {
new MoveBranchRequest(validPathLocation1, null, workspace2);
}
@@ -74,6 +77,18 @@
}
@Test
+ public void
shouldCreateValidRequestWithValidFromLocationAndValidToLocationAndValidBeforeLocation() {
+ Name newName = new BasicName("", "newName");
+ request = new MoveBranchRequest(validPathLocation1, validPathLocation2,
validPathLocation, workspace1, newName, NodeConflictBehavior.DO_NOT_REPLACE);
+ assertThat(request.from(), is(sameInstance(validPathLocation1)));
+ assertThat(request.into(), is(sameInstance(validPathLocation2)));
+ assertThat(request.before(), is(sameInstance(validPathLocation)));
+ assertThat(request.inWorkspace(), is(sameInstance(workspace1)));
+ assertThat(request.hasError(), is(false));
+ assertThat(request.getError(), is(nullValue()));
+ }
+
+ @Test
public void shouldConsiderEqualTwoRequestsWithSameLocations() {
request = new MoveBranchRequest(validPathLocation1, validPathLocation2,
workspace2);
MoveBranchRequest request2 = new MoveBranchRequest(validPathLocation1,
validPathLocation2, workspace2);
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-05-29 21:22:01
UTC (rev 954)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-06-02 19:30:41
UTC (rev 955)
@@ -1457,12 +1457,15 @@
throw new ItemNotFoundException();
}
// getLastSegment should return the only segment, since we verified that size()
== 1
- source = nodeInfo().getChildren().getChild(srcPath.getLastSegment());
+ Path.Segment sourceSegment = srcPath.getLastSegment();
+ source = nodeInfo().getChildren().getChild(sourceSegment);
if (source == null) {
- throw new ItemNotFoundException();
+ String workspaceName = this.cache.session().getWorkspace().getName();
+ throw new ItemNotFoundException(JcrI18n.pathNotFound.text(srcPath,
workspaceName));
}
Path destPath = null;
+ Path.Segment destSegment = null;
ChildNode destination = null;
if (destChildRelPath != null) {
@@ -1470,13 +1473,18 @@
if (destPath.isAbsolute() || destPath.size() != 1) {
throw new ItemNotFoundException();
}
+
+ destSegment = destPath.getLastSegment();
// getLastSegment should return the only segment, since we verified that
size() == 1
- destination = nodeInfo().getChildren().getChild(destPath.getLastSegment());
+ destination = nodeInfo().getChildren().getChild(destSegment);
if (destination == null) {
- throw new ItemNotFoundException();
+ String workspaceName = this.cache.session().getWorkspace().getName();
+ throw new ItemNotFoundException(JcrI18n.pathNotFound.text(destPath,
workspaceName));
}
}
+
+ this.editor().orderChildBefore(sourceSegment, destSegment);
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-05-29 21:22:01
UTC (rev 954)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-06-02 19:30:41
UTC (rev 955)
@@ -1343,6 +1343,32 @@
}
}
+ public void orderChildBefore(Path.Segment childToBeMoved, Path.Segment before)
throws RepositoryException {
+ PathFactory pathFactory = SessionCache.this.pathFactory;
+ Path thisPath = this.currentLocation.getPath();
+ UUID fromUuid = this.node.getChildren().getChild(childToBeMoved).getUuid();
+ Location fromLocation = Location.create(pathFactory.create(thisPath,
childToBeMoved), fromUuid);
+
+ Children children = this.node.getChildren();
+ ChildNode nodeToBeMoved = children.getChild(childToBeMoved);
+ this.node.removeChild(nodeToBeMoved.getUuid(), pathFactory);
+
+ if (before == null) {
+ this.node.addChild(nodeToBeMoved.getName(), nodeToBeMoved.getUuid(),
pathFactory);
+ // Moving the node into its parent will remove it from its current spot
in the child list and re-add it to the end
+ operations.move(fromLocation).into(this.currentLocation);
+
+ }
+ else {
+ Path beforePath = pathFactory.create(thisPath, before);
+ UUID beforeUuid = this.node.getChildren().getChild(before).getUuid();
+ Location beforeLocation = Location.create(beforePath, beforeUuid);
+
+ this.node.addChild(nodeToBeMoved.getName(), before,
nodeToBeMoved.getUuid(), pathFactory);
+ operations.move(fromLocation).before(beforeLocation);
+ }
+ }
+
/**
* Move the child specified by the supplied UUID to be a child of this node,
appending the child to the end of the current
* list of children. This method automatically disconnects the node from its
current parent.
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java 2009-05-29
21:22:01 UTC (rev 954)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedChildren.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -28,6 +28,7 @@
import java.util.UUID;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
/**
@@ -50,6 +51,13 @@
super(parentUuid);
}
+ protected ChangedChildren( ImmutableChildren original,
+ Name additionalChildName,
+ Path.Segment beforeChild,
+ UUID childUuid,
+ PathFactory pathFactory ) {
+ super(original, additionalChildName, beforeChild, childUuid, pathFactory);
+ }
/**
* {@inheritDoc}
*
@@ -66,6 +74,22 @@
}
/**
+ * Create another Children object that is equivalent to this node but with the
supplied child added before the named node.
+ *
+ * @param newChildName the name of the new child; may not be null
+ * @param beforeChild the path segment of the child before which this node should be
added; may not be null
+ * @param newChildUuid the UUID of the new child; may not be null
+ * @param pathFactory the factory that can be used to create Path and/or Path.Segment
instances.
+ * @return the new Children object; never null
+ */
+ public ChangedChildren with( Name newChildName,
+ Path.Segment beforeChild,
+ UUID newChildUuid,
+ PathFactory pathFactory ) {
+ return new ChangedChildren(this, newChildName, beforeChild, newChildUuid,
pathFactory);
+ }
+
+ /**
* {@inheritDoc}
*
* @see org.jboss.dna.jcr.cache.ImmutableChildren#without(java.util.UUID,
org.jboss.dna.graph.property.PathFactory)
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java 2009-05-29
21:22:01 UTC (rev 954)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ChangedNodeInfo.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -37,6 +37,7 @@
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NameFactory;
+import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.ValueFactories;
import org.jboss.dna.graph.property.ValueFactory;
@@ -287,6 +288,25 @@
}
return changedChildren.add(childName, childUuid, factory);
}
+
+ /**
+ * Add a child to the children. This method does nothing if the child is already in
the children.
+ *
+ * @param childName the name of the child that is to be added; may not be null
+ * @param childUuid the UUID of the child that is to be added; may not be null
+ * @param beforeChild the segment for the child that the new child should be added
before; may not be null
+ * @param factory the path factory that should be used to create a {@link Segment}
for the new {@link ChildNode} object
+ */
+ public void addChild( Name childName,
+ Path.Segment beforeChild,
+ UUID childUuid,
+ PathFactory factory ) {
+ if (changedChildren == null) {
+ // We need to capture the original children as a changed contained ...
+ changedChildren = new ChangedChildren(original.getChildren());
+ }
+ changedChildren = changedChildren.with(childName, beforeChild, childUuid,
factory);
+ }
/**
* Remove a child from the children. This method only uses the child's UUID to
identify the contained ChildNode instance that
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java 2009-05-29
21:22:01 UTC (rev 954)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableChildren.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -78,12 +78,40 @@
}
}
- protected ImmutableChildren( Children original,
+ protected ImmutableChildren( ImmutableChildren original,
Name additionalChildName,
+ Path.Segment beforeChild,
UUID childUuid,
PathFactory pathFactory ) {
- this(original);
- add(additionalChildName, childUuid, pathFactory);
+ assert beforeChild != null;
+
+ this.parentUuid = original.getParentUuid();
+ this.childrenByUuid = new HashMap<UUID, ChildNode>();
+ this.childrenByName = new LinkedListMultimap<Name, ChildNode>();
+
+ int snsIndex = 1;
+ boolean found = false;
+ ChildNode additionalChild = null;
+ for (ChildNode child : original.childrenByName.values()) {
+ this.childrenByUuid.put(child.getUuid(), child);
+ if (beforeChild.equals(child.getSegment())) {
+ Path.Segment segment = pathFactory.createSegment(additionalChildName,
snsIndex++);
+ additionalChild = new ChildNode(childUuid, segment);
+ childrenByName.put(child.getName(), additionalChild);
+ found = true;
+ }
+
+ if (found &&(child.getName().equals(additionalChildName))) {
+ Path.Segment newSegment =
pathFactory.createSegment(additionalChildName, snsIndex++);
+ childrenByName.put(child.getName(), child.with(newSegment));
+ }
+ else {
+ childrenByName.put(child.getName(), child);
+ }
+ }
+
+ assert additionalChild != null;
+ this.childrenByUuid.put(childUuid, additionalChild);
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableNodeInfo.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableNodeInfo.java 2009-05-29
21:22:01 UTC (rev 954)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/cache/ImmutableNodeInfo.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -199,4 +199,8 @@
public boolean isModified() {
return false;
}
+
+ public String toString() {
+ return this.uuid + " (" + primaryTypeName + ") {" +
properties + "}";
+ }
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-05-29 21:22:01 UTC
(rev 954)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-06-02 19:30:41 UTC
(rev 955)
@@ -35,6 +35,7 @@
import org.apache.jackrabbit.test.api.NodeCanAddMixinTest;
import org.apache.jackrabbit.test.api.NodeItemIsModifiedTest;
import org.apache.jackrabbit.test.api.NodeItemIsNewTest;
+import org.apache.jackrabbit.test.api.NodeOrderableChildNodesTest;
import org.apache.jackrabbit.test.api.NodeRemoveMixinTest;
import org.apache.jackrabbit.test.api.PropertyItemIsModifiedTest;
import org.apache.jackrabbit.test.api.PropertyItemIsNewTest;
@@ -181,7 +182,7 @@
addTestSuite(SessionUUIDTest.class);
// addTestSuite(NodeTest.class);
// addTestSuite(NodeUUIDTest.class);
- // addTestSuite(NodeOrderableChildNodesTest.class);
+ addTestSuite(NodeOrderableChildNodesTest.class);
addTestSuite(PropertyTest.class);
addTestSuite(SetValueBinaryTest.class);
Modified:
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
===================================================================
---
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -408,12 +408,15 @@
intoProjection.projection.getRules());
request.setError(new UnsupportedRequestException(msg));
}
+ SingleProjection beforeProjection = request.before() != null ?
asSingleProjection(workspace, request.before(), request) : null;
+
// Push down the request ...
Location fromLocation = Location.create(fromProjection.pathInSource);
Location intoLocation = Location.create(intoProjection.pathInSource);
+ Location beforeLocation = beforeProjection != null ?
Location.create(beforeProjection.pathInSource) : null;
String workspaceName = fromProjection.projection.getWorkspaceName();
- MoveBranchRequest sourceRequest = new MoveBranchRequest(fromLocation,
intoLocation, workspaceName, request.desiredName(),
+ MoveBranchRequest sourceRequest = new MoveBranchRequest(fromLocation,
intoLocation, beforeLocation, workspaceName, request.desiredName(),
request.conflictBehavior());
execute(sourceRequest, fromProjection.projection);
Modified:
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java
===================================================================
---
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -163,7 +163,7 @@
// Update the children to account for same-name siblings.
// This not only updates the FQN of the child nodes, but it also sets the
property that stores the
// the array of Path.Segment for the children (since the cache doesn't
maintain order).
- Path.Segment newSegment = updateChildList(cache, parentNode, request.named(),
getExecutionContext(), true);
+ Path.Segment newSegment = updateChildList(cache, parentNode, request.named(),
null, getExecutionContext(), true);
Node<Name, Object> node =
parentNode.addChild(Fqn.fromElements(newSegment));
assert checkChildren(parentNode);
@@ -244,6 +244,7 @@
node,
newParent,
desiredName,
+ null,
true,
useSameUuids,
newNodeUuid,
@@ -286,13 +287,32 @@
Path nodePath = request.from().getPath();
Node<Name, Object> node = getNode(request, cache, nodePath);
if (node == null) return;
- Path newParentPath = request.into().getPath();
+ Path newParentPath;
+
+ if (request.into() != null) {
+ newParentPath = request.into().getPath();
+ } else {
+ // into() and before() can't both be null
+ assert request.before() != null;
+ newParentPath = request.before().getPath().getParent();
+ }
+
+ Path.Segment beforeNodeName = request.before() != null ?
request.before().getPath().getLastSegment() : null;
Node<Name, Object> newParent = getNode(request, cache, newParentPath);
if (newParent == null) return;
// Copy the branch and use the same UUIDs ...
Name desiredName = request.desiredName();
- Path.Segment newSegment = copyNode(cache, node, newParent, desiredName, true,
true, null, null, getExecutionContext());
+ Path.Segment newSegment = copyNode(cache,
+ node,
+ newParent,
+ desiredName,
+ beforeNodeName,
+ true,
+ true,
+ null,
+ null,
+ getExecutionContext());
// Now delete the old node ...
Node<Name, Object> oldParent = node.getParent();
@@ -415,7 +435,7 @@
// Loop over each child and copy it ...
for (Node<Name, Object> child : fromRoot.getChildren()) {
- copyNode(intoCache, child, intoRoot, null, true, true, null, null, context);
+ copyNode(intoCache, child, intoRoot, null, null, true, true, null, null,
context);
}
// Copy the list of child segments in the root (this maintains the order of the
children) ...
@@ -518,10 +538,24 @@
}
+ /**
+ * @param newCache the cache into which the node is to be copied
+ * @param original the node to be copied
+ * @param newParent the new parent of the node to be copied
+ * @param desiredName the desired name of the node in the new location
+ * @param beforeNodeName the node before which the new node should be placed
+ * @param recursive if this is a deep copy
+ * @param reuseOriginalUuids indicates whether the original UUIDs should be used for
the copies or new UUIDs should be used
+ * @param uuidForCopyOfOriginal pre-determined UUID for copy of node; ignored if
reuseOriginalUuids is true
+ * @param count the count of nodes affected by the operation
+ * @param context the execution context that provides the path factory to be used to
create the new path name
+ * @return the path segment that identifies the new node under its new parent
+ */
protected Path.Segment copyNode( Cache<Name, Object> newCache,
Node<Name, Object> original,
Node<Name, Object> newParent,
Name desiredName,
+ Path.Segment beforeNodeName,
boolean recursive,
boolean reuseOriginalUuids,
UUID uuidForCopyOfOriginal,
@@ -530,13 +564,12 @@
assert original != null;
assert newParent != null;
// Get or create the new node ...
- Path.Segment name = desiredName != null ?
context.getValueFactories().getPathFactory().createSegment(desiredName) :
(Path.Segment)original.getFqn()
-
.getLastElement();
+ Path.Segment name = desiredName != null ?
context.getValueFactories().getPathFactory().createSegment(desiredName) :
(Path.Segment)original.getFqn().getLastElement();
// Update the children to account for same-name siblings.
// This not only updates the FQN of the child nodes, but it also sets the
property that stores the
// the array of Path.Segment for the children (since the cache doesn't
maintain order).
- Path.Segment newSegment = updateChildList(newCache, newParent, name.getName(),
context, true);
+ Path.Segment newSegment = updateChildList(newCache, newParent, name.getName(),
beforeNodeName, context, true);
Node<Name, Object> copy =
newParent.addChild(getFullyQualifiedName(newSegment));
assert checkChildren(newParent);
// Copy the properties ...
@@ -553,7 +586,7 @@
if (recursive) {
// Loop over each child and call this method ...
for (Node<Name, Object> child : original.getChildren()) {
- copyNode(newCache, child, copy, null, true, reuseOriginalUuids, null,
count, context);
+ copyNode(newCache, child, copy, null, null, true, reuseOriginalUuids,
null, count, context);
}
}
return newSegment;
@@ -569,6 +602,8 @@
* @param parent the parent node; may not be null
* @param changedName the name that should be compared to the existing node siblings
to determine whether the same-name
* sibling indexes should be updated; may not be null
+ * @param beforeNodeName the name of the node before which this node should be
placed; null indicates that this node should be
+ * added as the last child under the node
* @param context the execution context; may not be null
* @param addChildWithName true if a new child with the supplied name is to be added
to the children (but which does not yet
* exist in the node's children)
@@ -577,6 +612,7 @@
protected Path.Segment updateChildList( Cache<Name, Object> cache,
Node<Name, Object> parent,
Name changedName,
+ Path.Segment beforeNodeName,
ExecutionContext context,
boolean addChildWithName ) {
assert parent != null;
@@ -589,14 +625,25 @@
List<ChildInfo> childrenWithChangedName = new
LinkedList<ChildInfo>();
Path.Segment[] childNames =
(Path.Segment[])parent.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
int index = 0;
+ int snsIndex = 0;
+ boolean foundBeforeNode = false;
if (childNames != null) {
for (Path.Segment childName : childNames) {
+ if (childName.equals(beforeNodeName)) {
+ foundBeforeNode = true;
+ // And add a child info for the new node ...
+ ChildInfo info = new ChildInfo(null, snsIndex++);
+ childrenWithChangedName.add(info);
+ }
if (childName.getName().equals(changedName)) {
- ChildInfo info = new ChildInfo(childName, index);
+ ChildInfo info = new ChildInfo(childName, snsIndex);
childrenWithChangedName.add(info);
}
- index++;
+
+ snsIndex++;
+ if (!foundBeforeNode) index++;
}
+
}
if (addChildWithName) {
// Make room for the new child at the end of the array ...
@@ -605,15 +652,22 @@
} else {
int numExisting = childNames.length;
Path.Segment[] newChildNames = new Path.Segment[numExisting + 1];
- System.arraycopy(childNames, 0, newChildNames, 0, numExisting);
+ System.arraycopy(childNames, 0, newChildNames, 0, index);
+
+ if (index != numExisting) {
+ System.arraycopy(childNames, index, newChildNames, index + 1,
numExisting - index);
+ }
childNames = newChildNames;
}
- // And add a child info for the new node ...
- ChildInfo info = new ChildInfo(null, index);
- childrenWithChangedName.add(info);
+ if (!foundBeforeNode) {
+ // Make sure that we add a record for the new node if it hasn't
previously been added
+ ChildInfo info = new ChildInfo(null, index);
+ childrenWithChangedName.add(info);
+
+ }
Path.Segment newSegment =
context.getValueFactories().getPathFactory().createSegment(changedName);
- childNames[index++] = newSegment;
+ childNames[index] = newSegment;
}
assert childNames != null;
@@ -657,7 +711,7 @@
if (addChildWithName) {
// Return the segment for the new node ...
- return childNames[childNames.length - 1];
+ return childNames[index];
}
return null;
}
@@ -706,9 +760,8 @@
// don't copy ...
} else {
// Append an updated segment ...
- Path.Segment newSegment = context.getValueFactories()
- .getPathFactory()
- .createSegment(childName.getName(),
childName.getIndex() - 1);
+ Path.Segment newSegment =
context.getValueFactories().getPathFactory().createSegment(childName.getName(),
+
childName.getIndex() - 1);
newChildNames[index] = newSegment;
// Replace the child with the correct FQN ...
changeNodeName(cache, parent, childName, newSegment, context);
@@ -753,6 +806,10 @@
this.segment = childSegment;
this.childIndex = childIndex;
}
+
+ public String toString() {
+ return (segment != null ? segment.getString() : "null") +
"@" + childIndex;
+ }
}
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java 2009-05-29
21:22:01 UTC (rev 954)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java 2009-06-02
19:30:41 UTC (rev 955)
@@ -1360,6 +1360,7 @@
*
* @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.MoveBranchRequest)
*/
+ @SuppressWarnings( "unchecked" )
@Override
public void process( MoveBranchRequest request ) {
logger.trace(request.toString());
@@ -1390,6 +1391,20 @@
// Find the actual new location ...
Location toLocation = request.into();
+ Location beforeLocation = request.before();
+
+ if (beforeLocation != null) {
+ if (beforeLocation.hasPath()) {
+ toLocation = Location.create(beforeLocation.getPath().getParent());
+ } else {
+ ActualLocation actualBeforeLocation = getActualLocation(workspaceId,
beforeLocation);
+
+ // Ensure that the beforeLocation has a path - actualBeforeLocation
has a path
+ beforeLocation = actualBeforeLocation.location;
+ toLocation =
Location.create(actualBeforeLocation.location.getPath().getParent());
+ }
+ }
+
String toUuidString = null;
if (request.hasNoEffect()) {
actualNewLocation = actualOldLocation;
@@ -1416,28 +1431,69 @@
ns = fromEntity.getChildNamespace();
}
- // Find the largest SNS index in the existing ChildEntity objects
with the same name ...
- Query query =
entities.createNamedQuery("ChildEntity.findMaximumSnsIndex");
- query.setParameter("workspaceId", workspaceId);
- query.setParameter("parentUuid", toUuidString);
- query.setParameter("ns", ns.getId());
- query.setParameter("childName", childLocalName);
int nextSnsIndex = 1;
- try {
- Integer index = (Integer)query.getSingleResult();
- if (index != null) nextSnsIndex = index.intValue() + 1;
- } catch (NoResultException e) {
- }
+ int nextIndexInParent = 1;
+ if (beforeLocation == null) {
+ // Find the largest SNS index in the existing ChildEntity objects
with the same name ...
+ Query query =
entities.createNamedQuery("ChildEntity.findMaximumSnsIndex");
+ query.setParameter("workspaceId", workspaceId);
+ query.setParameter("parentUuid", toUuidString);
+ query.setParameter("ns", ns.getId());
+ query.setParameter("childName", childLocalName);
+ try {
+ Integer index = (Integer)query.getSingleResult();
+ if (index != null) nextSnsIndex = index.intValue() + 1;
+ } catch (NoResultException e) {
+ }
- // Find the largest child index in the existing ChildEntity objects
...
- query =
entities.createNamedQuery("ChildEntity.findMaximumChildIndex");
- query.setParameter("workspaceId", workspaceId);
- query.setParameter("parentUuid", toUuidString);
- int nextIndexInParent = 1;
- try {
- Integer index = (Integer)query.getSingleResult();
- if (index != null) nextIndexInParent = index + 1;
- } catch (NoResultException e) {
+ // Find the largest child index in the existing ChildEntity
objects ...
+ query =
entities.createNamedQuery("ChildEntity.findMaximumChildIndex");
+ query.setParameter("workspaceId", workspaceId);
+ query.setParameter("parentUuid", toUuidString);
+ try {
+ Integer index = (Integer)query.getSingleResult();
+ if (index != null) nextIndexInParent = index + 1;
+ } catch (NoResultException e) {
+ }
+ } else {
+ /*
+ * This is a sub-optimal approach, particularly for inserts to
the front
+ * of a long list of child nodes, but it guarantees that we
won't have
+ * the JPA-cached entities and the database out of sync.
+ */
+
+ Query query =
entities.createNamedQuery("ChildEntity.findAllUnderParent");
+ query.setParameter("workspaceId", workspaceId);
+ query.setParameter("parentUuidString", toUuidString);
+ try {
+ List<ChildEntity> children = query.getResultList();
+ Path beforePath = beforeLocation.getPath();
+ Path.Segment beforeSegment = beforePath.getLastSegment();
+
+ boolean foundBefore = false;
+ for (ChildEntity child : children) {
+ NamespaceEntity namespace = child.getChildNamespace();
+ if (namespace.getUri().equals(ns.getUri())
+ &&
child.getChildName().equals(childLocalName)
+ && child.getSameNameSiblingIndex() ==
beforeSegment.getIndex()) {
+ foundBefore = true;
+ nextIndexInParent = child.getIndexInParent();
+ nextSnsIndex = beforeSegment.getIndex();
+ }
+
+ if (foundBefore) {
+ child.setIndexInParent(child.getIndexInParent() +
1);
+ if (child.getChildName().equals(childLocalName)
+ &&
namespace.getUri().equals(ns.getUri())) {
+
child.setSameNameSiblingIndex(child.getSameNameSiblingIndex() + 1);
+ }
+ entities.persist(child);
+ }
+ }
+
+ } catch (NoResultException e) {
+ }
+
}
ChildId movedId = new ChildId(workspaceId, toUuidString,
fromUuidString);