Author: bcarothers
Date: 2009-06-20 11:13:29 -0400 (Sat, 20 Jun 2009)
New Revision: 1056
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/UuidAlreadyExistsException.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.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/UuidConflictBehavior.java
trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java
trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheLexicon.java
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java
trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessorTest.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java
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/ChildEntity.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/ChildId.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/PropertiesEntity.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/ReferenceEntity.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphNodeEntity.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQuery.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCache.java
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/Serializer.java
trunk/extensions/dna-connector-store-jpa/src/main/resources/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.properties
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectorWritingTest.java
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/BasicModelTest.java
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/ChildEntityTest.java
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQueryTest.java
Log:
DNA-370 JcrWorkspace.clone Is Not Implemented
Applied the attached patch (DNA-370_copy_behavior) to add support for UuidConflictBehavior
in the graph layer and each of the three connectors that currently support writes. This
includes the previous patch to modify the JPA connector and required some fairly heavy
modifications of the JBoss Cache connector to support efficient look-ups by UUID.
The patch also corrects some configuration to allow the JR TCK clone tests to start
working. This will result in one false negative in the nightly TCK compatibility build, as
there is a clone test that assumes the repository supports locking.
There is still some work left to be done to fully support clone. If removeExisting is
true, the JCR layer must first identify any conflicts and speculatively remove them to
make sure that removing the existing nodes won't violate type constraints. This check
cannot be done at the graph or connector layer, as those layers are unaware of the JCR
typing semantics. Additionally, the update method must still be implemented.
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-06-19 22:43:42 UTC
(rev 1055)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-06-20 15:13:29 UTC
(rev 1056)
@@ -568,7 +568,8 @@
protected Graph submit( String fromWorkspaceName,
Locations from,
Location into,
- Name childName ) {
+ Name childName,
+ UuidConflictBehavior uuidConflictBehavior ) {
String workspaceName = fromWorkspaceName != null ? fromWorkspaceName :
getCurrentWorkspaceName();
do {
requests.copyBranch(from.getLocation(),
@@ -577,7 +578,7 @@
getCurrentWorkspaceName(),
childName,
NodeConflictBehavior.APPEND,
- UuidConflictBehavior.ALWAYS_CREATE_NEW_UUID);
+ uuidConflictBehavior);
} while ((from = from.next()) != null);
return and();
}
@@ -2372,7 +2373,8 @@
protected BatchConjunction submit( String fromWorkspaceName,
Locations from,
Location into,
- Name copyName ) {
+ Name copyName,
+ UuidConflictBehavior
uuidConflictBehavior ) {
String workspaceName = fromWorkspaceName != null ? fromWorkspaceName
: getCurrentWorkspaceName();
do {
requestQueue.copyBranch(from.getLocation(),
@@ -2381,7 +2383,7 @@
workspaceName,
copyName,
null,
-
UuidConflictBehavior.ALWAYS_CREATE_NEW_UUID);
+ uuidConflictBehavior);
} while ((from = from.next()) != null);
return and();
}
@@ -4023,11 +4025,11 @@
* @param <Next> The interface that is to be returned when this request is
completed
*/
public interface WithUuids<Next> {
- Next removingMatchingUuids();
+ Next withNewUuids();
Next failingIfUuidsMatch();
- Next unlessMatchingUuidExists();
+ Next replacingExistingNodesWithSameUuids();
}
/**
@@ -5848,25 +5850,28 @@
* @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
+ * @param uuidConflictBehavior the behavior to be used for resolving any UUID
collisions that the copy request might
+ * create
* @return this object, for method chaining
*/
protected abstract T submit( String fromWorkspaceName,
- Locations from,
- Location into,
- Name nameForCopy );
+ Locations from,
+ Location into,
+ Name nameForCopy,
+ UuidConflictBehavior uuidConflictBehavior );
public FromWorkspace<CopyTarget<T>> failingIfUuidsMatch() {
this.uuidConflictBehavior = UuidConflictBehavior.THROW_EXCEPTION;
return this;
}
- public FromWorkspace<CopyTarget<T>> removingMatchingUuids() {
- this.uuidConflictBehavior = UuidConflictBehavior.REPLACE_EXISTING_NODE;
+ public FromWorkspace<CopyTarget<T>> withNewUuids() {
+ this.uuidConflictBehavior = UuidConflictBehavior.ALWAYS_CREATE_NEW_UUID;
return this;
}
- public FromWorkspace<CopyTarget<T>> unlessMatchingUuidExists() {
- this.uuidConflictBehavior = UuidConflictBehavior.DO_NOT_COPY;
+ public FromWorkspace<CopyTarget<T>>
replacingExistingNodesWithSameUuids() {
+ this.uuidConflictBehavior = UuidConflictBehavior.REPLACE_EXISTING_NODE;
return this;
}
@@ -5877,28 +5882,32 @@
}
public T into( Location into ) {
- return submit(this.fromWorkspaceName, this.from, into, null);
+ return submit(this.fromWorkspaceName, this.from, into, null,
this.uuidConflictBehavior);
}
public T into( Path into ) {
- return submit(this.fromWorkspaceName, this.from, Location.create(into),
null);
+ return submit(this.fromWorkspaceName, this.from, Location.create(into), null,
this.uuidConflictBehavior);
}
public T into( UUID into ) {
- return submit(this.fromWorkspaceName, this.from, Location.create(into),
null);
+ return submit(this.fromWorkspaceName, this.from, Location.create(into), null,
this.uuidConflictBehavior);
}
public T into( Property firstIdProperty,
Property... additionalIdProperties ) {
- return submit(this.fromWorkspaceName, this.from,
Location.create(firstIdProperty, additionalIdProperties), null);
+ return submit(this.fromWorkspaceName,
+ this.from,
+ Location.create(firstIdProperty, additionalIdProperties),
+ null,
+ this.uuidConflictBehavior);
}
public T into( Property into ) {
- return submit(this.fromWorkspaceName, this.from, Location.create(into),
null);
+ return submit(this.fromWorkspaceName, this.from, Location.create(into), null,
this.uuidConflictBehavior);
}
public T into( String into ) {
- return submit(this.fromWorkspaceName, this.from,
Location.create(createPath(into)), null);
+ return submit(this.fromWorkspaceName, this.from,
Location.create(createPath(into)), null, this.uuidConflictBehavior);
}
public T to( Location desiredLocation ) {
@@ -5910,7 +5919,11 @@
throw new
IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from,
desiredLocation));
}
Path parent = desiredPath.getParent();
- return submit(this.fromWorkspaceName, this.from, Location.create(parent),
desiredPath.getLastSegment().getName());
+ return submit(this.fromWorkspaceName,
+ this.from,
+ Location.create(parent),
+ desiredPath.getLastSegment().getName(),
+ this.uuidConflictBehavior);
}
public T to( Path desiredPath ) {
@@ -5918,7 +5931,11 @@
throw new
IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from, desiredPath));
}
Path parent = desiredPath.getParent();
- return submit(this.fromWorkspaceName, this.from, Location.create(parent),
desiredPath.getLastSegment().getName());
+ return submit(this.fromWorkspaceName,
+ this.from,
+ Location.create(parent),
+ desiredPath.getLastSegment().getName(),
+ this.uuidConflictBehavior);
}
public T to( String desiredPath ) {
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2009-06-19 22:43:42
UTC (rev 1055)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2009-06-20 15:13:29
UTC (rev 1056)
@@ -88,6 +88,7 @@
public static I18n errorImportingContent;
public static I18n unableToFindRepositorySourceWithName;
+ public static I18n nodeAlreadyExistsWithUuid;
/* In-Memory Connector */
public static I18n inMemoryNodeDoesNotExist;
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/UuidAlreadyExistsException.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/UuidAlreadyExistsException.java
(rev 0)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/UuidAlreadyExistsException.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -0,0 +1,24 @@
+package org.jboss.dna.graph.connector;
+
+import java.util.UUID;
+import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.request.CopyBranchRequest;
+import org.jboss.dna.graph.request.UuidConflictBehavior;
+
+/**
+ * Exception that indicates that a copy request failed because one of the UUIDs in the
source branch already exists in the target
+ * workspace and the {@link CopyBranchRequest#uuidConflictBehavior() UUID conflict
behavior} is set to
+ * {@link UuidConflictBehavior#THROW_EXCEPTION}.
+ */
+public class UuidAlreadyExistsException extends RepositorySourceException {
+
+ private static final long serialVersionUID = 1L;
+
+ public UuidAlreadyExistsException( String repositorySourceName,
+ UUID uuid,
+ String pathAsString,
+ String workspaceName ) {
+ super(repositorySourceName, GraphI18n.nodeAlreadyExistsWithUuid.text(uuid,
pathAsString, workspaceName));
+ }
+
+}
Property changes on:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/UuidAlreadyExistsException.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
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-06-19
22:43:42 UTC (rev 1055)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ForkRequestProcessor.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -1262,8 +1262,7 @@
// Create the pushed-down request ...
CopyBranchRequest pushDown = new CopyBranchRequest(fromProxy.location(),
fromProxy.workspaceName(), intoProxy.location(),
intoProxy.workspaceName(),
request.desiredName(),
-
request.nodeConflictBehavior(),
-
request.uuidConflictBehavior());
+
request.nodeConflictBehavior(), request.uuidConflictBehavior());
// Create the federated request ...
FederatedRequest federatedRequest = new FederatedRequest(request);
federatedRequest.add(pushDown, sameLocation, false, fromProxy.projection(),
intoProxy.projection());
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-06-19
22:43:42 UTC (rev 1055)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -40,6 +41,7 @@
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
+import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.Property;
import org.jboss.dna.graph.property.PropertyFactory;
import org.jboss.dna.graph.property.PropertyType;
@@ -229,6 +231,30 @@
}
/**
+ * Returns the absolute path to the given node
+ *
+ * @param pathFactory the path factory to use to create the path from the list of
names of all of the nodes on the path
+ * from the root node to the given node
+ * @param node the node for which the path should be returned
+ * @return the absolute path to the given node
+ */
+ Path pathFor( PathFactory pathFactory,
+ InMemoryNode node ) {
+ assert node != null;
+ assert pathFactory != null;
+
+ LinkedList<Path.Segment> segments = new
LinkedList<Path.Segment>();
+ InMemoryNode root = getRoot();
+
+ do {
+ segments.addFirst(node.getName());
+ node = node.getParent();
+ } while (!node.equals(root));
+
+ return pathFactory.createAbsolutePath(segments);
+ }
+
+ /**
* Find the lowest existing node along the path.
*
* @param path the path to the node; may not be null
@@ -358,12 +384,12 @@
Name desiredNewName,
Workspace newWorkspace,
InMemoryNode newParent,
- InMemoryNode beforeNode) {
+ InMemoryNode beforeNode ) {
assert context != null;
assert newParent != null;
assert node != null;
-// Why was this restriction here? -- BRC
-// 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();
@@ -379,16 +405,15 @@
newName = desiredNewName;
node.setName(context.getValueFactories().getPathFactory().createSegment(desiredNewName,
1));
}
-
+
if (beforeNode == null) {
newParent.getChildren().add(node);
- }
- else {
+ } 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 ...
@@ -434,14 +459,13 @@
assert original != null;
assert newParent != null;
assert newWorkspace != null;
- if (this.equals(newWorkspace) && oldToNewUuids == null) oldToNewUuids
= new HashMap<UUID, UUID>();
boolean reuseUuids = oldToNewUuids == null;
// Get or create the new node ...
Name childName = desiredName != null ? desiredName :
original.getName().getName();
UUID uuidForCopy = reuseUuids ? original.getUuid() : UUID.randomUUID();
InMemoryNode copy = newWorkspace.createNode(context, newParent, childName,
uuidForCopy);
- if (oldToNewUuids != null) {
+ if (!reuseUuids) {
oldToNewUuids.put(original.getUuid(), copy.getUuid());
}
@@ -455,7 +479,7 @@
}
}
- if (oldToNewUuids != null) {
+ if (!reuseUuids) {
// Now, adjust any references in the new subgraph to objects in the
original subgraph
// (because they were internal references, and need to be internal to the
new subgraph)
PropertyFactory propertyFactory = context.getPropertyFactory();
@@ -498,6 +522,22 @@
return copy;
}
+ public Set<UUID> getUuidsUnderNode( InMemoryNode node ) {
+ Set<UUID> uuids = new HashSet<UUID>();
+ uuidsUnderNode(node, uuids);
+
+ return uuids;
+ }
+
+ private void uuidsUnderNode( InMemoryNode node,
+ Set<UUID> accumulator ) {
+ accumulator.add(node.getUuid());
+
+ for (InMemoryNode child : node.getChildren()) {
+ uuidsUnderNode(child, accumulator);
+ }
+ }
+
protected void correctSameNameSiblingIndexes( ExecutionContext context,
InMemoryNode parentNode,
Name name ) {
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-06-19
22:43:42 UTC (rev 1055)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRequestProcessor.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -38,7 +38,9 @@
import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.connector.RepositoryContext;
+import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NamespaceRegistry;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.PathNotFoundException;
@@ -119,11 +121,51 @@
if (workspace == null || newWorkspace == null) return;
InMemoryNode node = getTargetNode(workspace, request, request.from());
if (node == null) return;
+
+ Map<UUID, UUID> copyMap = null;
+ Set<UUID> uuidsInFromBranch = null;
+
+ switch (request.uuidConflictBehavior()) {
+ case ALWAYS_CREATE_NEW_UUID:
+
+ /*
+ * The copyNode method uses the presence of a non-null map as an
indicator that new UUIDs should be created
+ * during the copy operation
+ */
+ copyMap = new HashMap<UUID, UUID>();
+ break;
+ case REPLACE_EXISTING_NODE:
+ uuidsInFromBranch = workspace.getUuidsUnderNode(node);
+
+ for (UUID uuid : uuidsInFromBranch) {
+ InMemoryNode existing;
+ if (null != (existing = newWorkspace.getNode(uuid))) {
+ newWorkspace.removeNode(this.getExecutionContext(), existing);
+ }
+ }
+ break;
+ case THROW_EXCEPTION:
+ uuidsInFromBranch = workspace.getUuidsUnderNode(node);
+
+ for (UUID uuid : uuidsInFromBranch) {
+ InMemoryNode existing;
+ if (null != (existing = newWorkspace.getNode(uuid))) {
+ NamespaceRegistry namespaces =
this.getExecutionContext().getNamespaceRegistry();
+ String path = newWorkspace.pathFor(pathFactory,
existing).getString(namespaces);
+ request.setError(new
UuidAlreadyExistsException(this.getSourceName(), uuid, path, newWorkspace.getName()));
+ return;
+ }
+ }
+ break;
+
+ default:
+ throw new IllegalStateException("Unexpected UUID conflict behavior:
" + request.uuidConflictBehavior());
+ }
+
// Look up the new parent, which must exist ...
Path newParentPath = request.into().getPath();
Name desiredName = request.desiredName();
InMemoryNode newParent = newWorkspace.getNode(newParentPath);
- Map<UUID, UUID> copyMap = workspace.equals(newWorkspace) ? new
HashMap<UUID, UUID>() : null;
InMemoryNode newNode = workspace.copyNode(getExecutionContext(),
node,
newWorkspace,
@@ -222,24 +264,23 @@
if (node == null) return;
// Look up the new parent, which must exist ...
Path newParentPath;
-
+
if (request.into() != null) {
newParentPath = request.into().getPath();
- }
- else {
+ } 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, beforeNode);
assert node.getParent() == newParent;
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UuidConflictBehavior.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UuidConflictBehavior.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UuidConflictBehavior.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -9,7 +9,6 @@
public enum UuidConflictBehavior {
ALWAYS_CREATE_NEW_UUID,
- DO_NOT_COPY,
REPLACE_EXISTING_NODE,
THROW_EXCEPTION;
}
Modified: trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
===================================================================
--- trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2009-06-19
22:43:42 UTC (rev 1055)
+++ trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2009-06-20
15:13:29 UTC (rev 1056)
@@ -75,6 +75,7 @@
errorImportingContent = Error importing {0} content from {1}
unableToFindRepositorySourceWithName = Unable to find a repository source named
"{0}"
+nodeAlreadyExistsWithUuid = A node with UUID "{0}" already exists at path
"{1}" in workspace "{2}"
# In-memory connector
inMemoryNodeDoesNotExist = Could not find an existing node at {0}
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-06-19
22:43:42 UTC (rev 1055)
+++
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -25,12 +25,16 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.jboss.dna.graph.IsNodeWithChildren.hasChild;
import static org.jboss.dna.graph.IsNodeWithChildren.hasChildren;
import static org.jboss.dna.graph.IsNodeWithChildren.isEmpty;
import static org.jboss.dna.graph.IsNodeWithProperty.hasProperty;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNoException;
+import java.util.UUID;
import org.jboss.dna.common.statistic.Stopwatch;
import org.jboss.dna.common.util.IoUtil;
import org.jboss.dna.graph.DnaLexicon;
@@ -38,8 +42,11 @@
import org.jboss.dna.graph.Node;
import org.jboss.dna.graph.Subgraph;
import org.jboss.dna.graph.connector.RepositorySource;
+import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
+import org.jboss.dna.graph.property.PathNotFoundException;
import org.jboss.dna.graph.property.Reference;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
/**
@@ -68,6 +75,14 @@
IoUtil.read(getClass().getClassLoader().getResourceAsStream("LoremIpsum3.txt"))};
}
+ protected void tryCreatingAWorkspaceNamed( String workspaceName ) {
+ try {
+ graph.createWorkspace().named(workspaceName);
+ } catch (Exception ex) {
+ assumeNoException(ex);
+ }
+ }
+
/**
* These tests require that the source supports updates, since all of the tests do
some form of updates.
*/
@@ -105,19 +120,9 @@
@Test
public void shouldAddChildrenAndSettingProperties() {
- graph.batch()
- .set("propA")
- .to("valueA")
- .on("/")
- .and()
- .create("/a")
- .with("propB", "valueB")
- .and("propC", "valueC")
- .and()
- .create("/b")
- .with("propD", "valueD")
- .and("propE", "valueE")
- .execute();
+
graph.batch().set("propA").to("valueA").on("/").and().create("/a").with("propB",
"valueB").and("propC",
"valueC").and().create("/b").with("propD",
+
"valueD").and("propE",
+
"valueE").execute();
// Now look up the root node ...
Node root = graph.getNodeAt("/");
assertThat(root, is(notNullValue()));
@@ -303,6 +308,7 @@
createSubgraph(graph, initialPath, depth, numChildrenPerNode,
numPropertiesPerNode, batch, sw, System.out, description);
}
+ @Ignore
@Test
public void shouldCreateTreeWith10ChildrenAnd2LevelsDeepUsingIndividualRequests() {
String initialPath = "";
@@ -314,6 +320,7 @@
createSubgraph(graph, initialPath, depth, numChildrenPerNode,
numPropertiesPerNode, batch, sw, System.out, null);
}
+ @Ignore
@Test
public void shouldCreateTreeWith10ChildrenAnd2LevelsDeepUsingOneBatch() {
String initialPath = "";
@@ -325,6 +332,7 @@
createSubgraph(graph, initialPath, depth, numChildrenPerNode,
numPropertiesPerNode, batch, sw, System.out, null);
}
+ @Ignore
@Test
public void shouldCreateTreeWith10ChildrenAnd3LevelsDeepUsingOneBatch() {
String initialPath = "";
@@ -810,6 +818,178 @@
"The quick
brown fox jumped over the moon. What? "));
}
+ @Test
+ public void shouldCopyChildrenBetweenWorkspacesWithNewUuids() throws Exception {
+ String defaultWorkspaceName = graph.getCurrentWorkspaceName();
+ String workspaceName = "copyChildrenSource";
+
+ tryCreatingAWorkspaceNamed(workspaceName);
+
+ graph.useWorkspace(workspaceName);
+ 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);
+
+ Subgraph source = graph.getSubgraphOfDepth(3).at("/node1");
+
+ graph.useWorkspace(defaultWorkspaceName);
+
+ graph.create("/newUuids");
+
graph.copy("/node1").withNewUuids().fromWorkspace(workspaceName).to("/newUuids/node1");
+
+ /*
+ * Focus on testing node structure, since shouldCopyNodeWithChildren tests that
properties get copied
+ */
+ Subgraph target = graph.getSubgraphOfDepth(3).at("/newUuids/node1");
+ assertThat(target, is(notNullValue()));
+ assertThat(target.getNode(".").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode(".")),
not(uuidFor(source.getNode("."))));
+ assertThat(target.getNode("node1").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode("node1")),
not(uuidFor(source.getNode("node1"))));
+ assertThat(target.getNode("node2").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode("node2")),
not(uuidFor(source.getNode("node2"))));
+ assertThat(target.getNode("node3").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode("node3")),
not(uuidFor(source.getNode("node3"))));
+
+ }
+
+ @Test
+ public void shouldCopyChildrenBetweenWorkspacesPreservingUuids() throws Exception {
+ String defaultWorkspaceName = graph.getCurrentWorkspaceName();
+ String workspaceName = "copyChildrenSource";
+
+ tryCreatingAWorkspaceNamed(workspaceName);
+
+ graph.useWorkspace(workspaceName);
+ 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);
+
+ Subgraph source = graph.getSubgraphOfDepth(3).at("/node1");
+
+ graph.useWorkspace(defaultWorkspaceName);
+
+ graph.create("/newUuids");
+
graph.copy("/node1").replacingExistingNodesWithSameUuids().fromWorkspace(workspaceName).to("/newUuids/node1");
+
+ /*
+ * Focus on testing node structure, since shouldCopyNodeWithChildren tests that
properties get copied
+ */
+ Subgraph target = graph.getSubgraphOfDepth(3).at("/newUuids/node1");
+ assertThat(target, is(notNullValue()));
+ assertThat(target.getNode(".").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode(".")),
is(uuidFor(source.getNode("."))));
+ assertThat(target.getNode("node1").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode("node1")),
is(uuidFor(source.getNode("node1"))));
+ assertThat(target.getNode("node2").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode("node2")),
is(uuidFor(source.getNode("node2"))));
+ assertThat(target.getNode("node3").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode("node3")),
is(uuidFor(source.getNode("node3"))));
+
+ }
+
+ @Test
+ public void shouldNotCopyChildrenBetweenWorkspacesIfUuidConflictAndFailureBehavior()
throws Exception {
+ String defaultWorkspaceName = graph.getCurrentWorkspaceName();
+ String workspaceName = "copyChildrenSource";
+
+ tryCreatingAWorkspaceNamed(workspaceName);
+
+ graph.useWorkspace(workspaceName);
+ 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);
+
+ graph.useWorkspace(defaultWorkspaceName);
+
+ graph.create("/newUuids");
+ // Copy once to get the UUID into the default workspace
+
graph.copy("/node1/node1/node1").failingIfUuidsMatch().fromWorkspace(workspaceName).to("/newUuids/node1");
+
+ try {
+ // Copy again to get the exception since the UUID is already in the default
workspace
+
graph.copy("/node1/node1").failingIfUuidsMatch().fromWorkspace(workspaceName).to("/newUuids/shouldNotWork");
+ fail("Should not be able to copy a node into a workspace if another node
with the "
+ + "same UUID already exists in the workspace and UUID behavior is
failingIfUuidsMatch");
+ } catch (UuidAlreadyExistsException ex) {
+ // Expected
+ }
+
+ }
+
+ @Test
+ public void
shouldCopyChildrenBetweenWorkspacesAndRemoveExistingNodesWithSameUuidIfSpecified() throws
Exception {
+ String defaultWorkspaceName = graph.getCurrentWorkspaceName();
+ String workspaceName = "copyChildrenSource";
+
+ tryCreatingAWorkspaceNamed(workspaceName);
+
+ graph.useWorkspace(workspaceName);
+ 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);
+
+ Subgraph source = graph.getSubgraphOfDepth(3).at("/node1");
+
+ graph.useWorkspace(defaultWorkspaceName);
+
+ graph.create("/newUuids");
+ // Copy once to get the UUID into the default workspace
+
graph.copy("/node1").replacingExistingNodesWithSameUuids().fromWorkspace(workspaceName).to("/newUuids/node1");
+
+ // Create a new child node that in the target workspace that has no corresponding
node in the source workspace
+ graph.create("/newUuids/node1/shouldBeRemoved");
+
+ // Copy again to test the behavior now that the UUIDs are already in the default
workspace
+ // This should remove /newUuids/node1/shouldBeRemoved
+
graph.copy("/node1").replacingExistingNodesWithSameUuids().fromWorkspace(workspaceName).to("/newUuids/otherNode");
+
+ /*
+ * Focus on testing node structure, since shouldCopyNodeWithChildren tests that
properties get copied
+ */
+ // /newUuids/node1 should have been removed when the new node was added with the
same UUID
+ assertThat(graph.getNodeAt("/newUuids").getChildren(),
hasChildren(segment("otherNode")));
+
+ try {
+ graph.getNodeAt("/newUuids/node1/shouldBeRemoved");
+ fail("/newUuids/node1/shouldBeRemoved should no longer exist after the
copy-with-remove-conflicting-uuids operation");
+ }
+ catch (PathNotFoundException pnfe) {
+ // Expected
+ }
+
+ Subgraph target =
graph.getSubgraphOfDepth(3).at("/newUuids/otherNode");
+ assertThat(target, is(notNullValue()));
+ assertThat(target.getNode(".").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode(".")),
is(uuidFor(source.getNode("."))));
+ assertThat(target.getNode("node1").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode("node1")),
is(uuidFor(source.getNode("node1"))));
+ assertThat(target.getNode("node2").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode("node2")),
is(uuidFor(source.getNode("node2"))));
+ assertThat(target.getNode("node3").getChildren(),
hasChildren(segment("node1"), segment("node2"),
segment("node3")));
+ assertThat(uuidFor(target.getNode("node3")),
is(uuidFor(source.getNode("node3"))));
+ }
+
+ private UUID uuidFor( Node node ) {
+ return (UUID)node.getProperty(DnaLexicon.UUID).getFirstValue();
+ }
+
protected void assertReference( String fromNodePath,
String propertyName,
String... toNodePath ) {
@@ -1463,12 +1643,15 @@
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"),
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");
@@ -1490,80 +1673,89 @@
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?
"));
+
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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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?
"));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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?
"));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "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? "));
+ "The quick
brown fox jumped over the moon. What? "));
}
}
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-06-19 22:43:42
UTC (rev 1055)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-06-20 15:13:29
UTC (rev 1056)
@@ -24,8 +24,8 @@
package org.jboss.dna.jcr;
import java.io.InputStream;
+import java.security.AccessControlException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
@@ -36,6 +36,7 @@
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;
+import javax.jcr.AccessDeniedException;
import javax.jcr.InvalidItemStateException;
import javax.jcr.Item;
import javax.jcr.ItemExistsException;
@@ -98,6 +99,8 @@
abstract boolean isRoot();
+ public abstract AbstractJcrNode getParent() throws ItemNotFoundException,
RepositoryException;
+
final UUID internalUuid() {
return nodeUuid;
}
@@ -995,26 +998,6 @@
return cache.findJcrNode(child.getUuid());
}
- /**
- * {@inheritDoc}
- *
- * @see javax.jcr.Node#update(java.lang.String)
- */
- public final void update( String srcWorkspaceName ) throws NoSuchWorkspaceException,
RepositoryException {
- String[] workspaces = this.session().workspace().getAccessibleWorkspaceNames();
-
- if (!Arrays.asList(workspaces).contains(srcWorkspaceName)) {
- JcrRepository repo = session().repository();
- throw new
NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(srcWorkspaceName,
repo.getName()));
- }
-
- if (session().hasPendingChanges()) {
- throw new InvalidItemStateException(JcrI18n.noPendingChangesAllowed.text());
- }
-
- if (true) throw new UnsupportedOperationException();
- }
-
protected final Property removeExistingValuedProperty( String name ) throws
ConstraintViolationException, RepositoryException {
PropertyId id = new PropertyId(nodeUuid, nameFrom(name));
AbstractJcrProperty property = cache.findJcrProperty(id);
@@ -1377,23 +1360,71 @@
*
* @see javax.jcr.Node#getCorrespondingNodePath(java.lang.String)
*/
- public final String getCorrespondingNodePath( String workspaceName ) throws
NoSuchWorkspaceException, RepositoryException {
-
- String[] workspaces = this.session().workspace().getAccessibleWorkspaceNames();
+ final Path correspondingNodePathFrom( String workspaceName )
+ throws NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
- if (!Arrays.asList(workspaces).contains(workspaceName)) {
- JcrRepository repo = session().repository();
- throw new
NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(workspaceName,
repo.getName()));
+ assert workspaceName != null;
+
+ NamespaceRegistry namespaces = this.context().getNamespaceRegistry();
+
+ AbstractJcrNode referenceableRoot = this;
+ while
(!referenceableRoot.isNodeType(JcrMixLexicon.REFERENCEABLE.getString(namespaces))) {
+ referenceableRoot = referenceableRoot.getParent();
}
- // TODO:Check permissions on workspace
-
- throw new UnsupportedOperationException();
+ UUID uuid = referenceableRoot.internalUuid();
+ Path relativePath = path().equals(referenceableRoot.path()) ? null :
path().relativeTo(referenceableRoot.path());
+
+ Path correspondingPath = this.cache.getPathFor(workspaceName, uuid,
relativePath);
+
+ try {
+ this.session().checkPermission(workspaceName, correspondingPath,
"read");
+ } catch (AccessControlException ace) {
+ throw new AccessDeniedException(ace);
+ }
+
+ return correspondingPath;
}
/**
* {@inheritDoc}
*
+ * @see javax.jcr.Node#getCorrespondingNodePath(java.lang.String)
+ */
+ public final String getCorrespondingNodePath( String workspaceName )
+ throws NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
+
+ CheckArg.isNotNull(workspaceName, "workspace name");
+ return correspondingNodePathFrom(workspaceName).getString(this.namespaces());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see javax.jcr.Node#update(java.lang.String)
+ */
+ @SuppressWarnings( "unused" )
+ public final void update( String srcWorkspaceName ) throws NoSuchWorkspaceException,
RepositoryException {
+ CheckArg.isNotNull(srcWorkspaceName, "workspace name");
+
+ Path correspondingPath;
+
+ if (session().hasPendingChanges()) {
+ throw new InvalidItemStateException(JcrI18n.noPendingChangesAllowed.text());
+ }
+
+ try {
+ correspondingPath = correspondingNodePathFrom(srcWorkspaceName);
+ } catch (ItemNotFoundException infe) {
+ return;
+ }
+
+ if (true) throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @throws UnsupportedRepositoryOperationException always
* @see javax.jcr.Node#getVersionHistory()
*/
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java 2009-06-19
22:43:42 UTC (rev 1055)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrContentHandler.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -371,9 +371,8 @@
ByteArrayInputStream is = new
ByteArrayInputStream(Base64.decode(s, Base64.URL_SAFE));
currentProps.get(currentPropName).add(session.getValueFactory().createValue(is));
} else {
- currentProps.get(currentPropName).add(session.getValueFactory()
-
.createValue(SYSTEM_VIEW_NAME_DECODER.decode(s),
-
currentPropType));
+
currentProps.get(currentPropName).add(session.getValueFactory().createValue(SYSTEM_VIEW_NAME_DECODER.decode(s),
+
currentPropType));
}
} catch (RepositoryException re) {
throw new EnclosingSAXException(re);
@@ -430,7 +429,7 @@
if (existingNodeWithUuid != null) {
switch (uuidBehavior) {
case
ImportUUIDBehavior.IMPORT_UUID_COLLISION_REPLACE_EXISTING:
- parentNode =
(AbstractJcrNode)existingNodeWithUuid.getParent();
+ parentNode = existingNodeWithUuid.getParent();
parentNode.editorFor(operations()).destroyChild(uuid);
break;
case ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW:
@@ -440,7 +439,7 @@
if
(existingNodeWithUuid.path().isAtOrAbove(parentStack.firstElement().path())) {
throw new ConstraintViolationException();
}
- AbstractJcrNode temp =
(AbstractJcrNode)existingNodeWithUuid.getParent();
+ AbstractJcrNode temp = existingNodeWithUuid.getParent();
temp.editorFor(operations()).destroyChild(uuid);
break;
case ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW:
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-06-19 22:43:42 UTC
(rev 1055)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-06-20 15:13:29 UTC
(rev 1056)
@@ -46,6 +46,8 @@
public static I18n repositoryDoesNotExist;
public static I18n fileDoesNotExist;
+ public static I18n rootNodeHasNoParent;
+
public static I18n noNamespaceWithPrefix;
public static I18n noNamespaceWithUri;
public static I18n unableToChangeTheDefaultNamespace;
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-06-19 22:43:42 UTC
(rev 1055)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-06-20 15:13:29 UTC
(rev 1056)
@@ -25,7 +25,6 @@
import java.util.UUID;
import javax.jcr.ItemNotFoundException;
-import javax.jcr.Node;
import javax.jcr.RepositoryException;
import net.jcip.annotations.NotThreadSafe;
@@ -73,7 +72,7 @@
*
* @see javax.jcr.Item#getParent()
*/
- public Node getParent() throws ItemNotFoundException, RepositoryException {
+ public AbstractJcrNode getParent() throws ItemNotFoundException, RepositoryException
{
return cache.findJcrNode(nodeInfo().getParent());
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java 2009-06-19 22:43:42 UTC
(rev 1055)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRootNode.java 2009-06-20 15:13:29 UTC
(rev 1056)
@@ -26,7 +26,6 @@
import java.util.UUID;
import javax.jcr.Item;
import javax.jcr.ItemNotFoundException;
-import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.nodetype.ConstraintViolationException;
import net.jcip.annotations.NotThreadSafe;
@@ -89,8 +88,8 @@
* @throws ItemNotFoundException always
* @see javax.jcr.Item#getParent()
*/
- public Node getParent() throws ItemNotFoundException {
- throw new ItemNotFoundException();
+ public AbstractJcrNode getParent() throws ItemNotFoundException {
+ throw new ItemNotFoundException(JcrI18n.rootNodeHasNoParent.text());
}
/**
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-06-19 22:43:42
UTC (rev 1055)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-06-20 15:13:29
UTC (rev 1056)
@@ -53,6 +53,7 @@
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.NameFactory;
import org.jboss.dna.graph.property.Path;
@@ -259,8 +260,93 @@
public void clone( String srcWorkspace,
String srcAbsPath,
String destAbsPath,
- boolean removeExisting ) {
- throw new UnsupportedOperationException();
+ boolean removeExisting )
+ throws ConstraintViolationException, VersionException, AccessDeniedException,
PathNotFoundException, ItemExistsException,
+ LockException, RepositoryException {
+ 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();
+ }
+
+ try {
+ this.session.checkPermission(destPath.getParent(), "add_node");
+ } catch (AccessControlException ace) {
+ throw new AccessDeniedException(ace);
+ }
+
+ /*
+ * Make sure that the node has a definition at the new location
+ */
+ SessionCache cache = this.session.cache();
+ NodeInfo cacheParent = cache.findNodeInfo(null, destPath.getParent());
+
+ // Skip the cache and load the latest parent info directly from the graph
+ NodeInfo parent = cache.loadFromGraph(null, cacheParent.getUuid());
+ Name newNodeName = destPath.getLastSegment().getName();
+ String parentPath =
destPath.getParent().getString(this.context.getNamespaceRegistry());
+
+ // This will check for a definition and throw a ConstraintViolationException or
ItemExistsException if none is found
+ graph.useWorkspace(srcWorkspace);
+ Property primaryTypeProp;
+ Property uuidProp;
+ try {
+ Map<Name, Property> props =
graph.getNodeAt(srcPath).getPropertiesByName();
+ primaryTypeProp = props.get(JcrLexicon.PRIMARY_TYPE);
+ uuidProp = props.get(DnaLexicon.UUID);
+ } catch (org.jboss.dna.graph.property.PathNotFoundException pnfe) {
+ throw new PathNotFoundException(JcrI18n.itemNotFoundAtPath.text(srcAbsPath,
srcWorkspace));
+ } finally {
+ graph.useWorkspace(this.name);
+ }
+
+ assert primaryTypeProp != null : "Cannot have a node in a JCR repository
with no jcr:primaryType property";
+ assert uuidProp != null : "Cannot have a node in a JCR repository with no
UUID";
+
+ NameFactory nameFactory = this.context.getValueFactories().getNameFactory();
+ this.session.cache().findBestNodeDefinition(parent,
+ parentPath,
+ newNodeName,
+
nameFactory.create(primaryTypeProp.getFirstValue()));
+
+ // Perform the copy operation, but use the "to" form (not the
"into", which takes the parent) ...
+ // graph.copy(srcPath).fromWorkspace(srcWorkspace).to(destPath);
+ if (removeExisting) {
+
graph.copy(srcPath).replacingExistingNodesWithSameUuids().fromWorkspace(srcWorkspace).to(destPath);
+ } else {
+ try {
+
graph.copy(srcPath).failingIfUuidsMatch().fromWorkspace(srcWorkspace).to(destPath);
+ } catch (UuidAlreadyExistsException uaee) {
+ throw new ItemExistsException(uaee.getMessage());
+ }
+ }
+
+ assert uuidProp.getFirstValue() instanceof UUID;
+ // Load the node that we just copied
+ cache.compensateForWorkspaceChildChange(cacheParent.getUuid(), null,
(UUID)uuidProp.getFirstValue(), newNodeName);
+
}
/**
@@ -330,10 +416,19 @@
// This will check for a definition and throw a ConstraintViolationException or
ItemExistsException if none is found
graph.useWorkspace(srcWorkspace);
- Property primaryTypeProp =
graph.getNodeAt(srcPath).getProperty(JcrLexicon.PRIMARY_TYPE);
- Property uuidProp = graph.getNodeAt(srcPath).getProperty(DnaLexicon.UUID);
- graph.useWorkspace(this.name);
+ Property primaryTypeProp;
+ Property uuidProp;
+ try {
+ Map<Name, Property> props =
graph.getNodeAt(srcPath).getPropertiesByName();
+ primaryTypeProp = props.get(JcrLexicon.PRIMARY_TYPE);
+ uuidProp = props.get(DnaLexicon.UUID);
+ } catch (org.jboss.dna.graph.property.PathNotFoundException pnfe) {
+ throw new PathNotFoundException(JcrI18n.itemNotFoundAtPath.text(srcAbsPath,
srcWorkspace));
+ } finally {
+ graph.useWorkspace(this.name);
+ }
+
assert primaryTypeProp != null : "Cannot have a node in a JCR repository
with no jcr:primaryType property";
assert uuidProp != null : "Cannot have a node in a JCR repository with no
UUID";
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-06-19 22:43:42
UTC (rev 1055)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-06-20 15:13:29
UTC (rev 1056)
@@ -42,6 +42,7 @@
import javax.jcr.Item;
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
+import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.PropertyType;
@@ -74,6 +75,7 @@
import org.jboss.dna.graph.request.BatchRequestBuilder;
import org.jboss.dna.graph.request.ChangeRequest;
import org.jboss.dna.graph.request.CreateNodeRequest;
+import org.jboss.dna.graph.request.InvalidWorkspaceException;
import org.jboss.dna.graph.request.Request;
import org.jboss.dna.jcr.cache.ChangedNodeInfo;
import org.jboss.dna.jcr.cache.ChildNode;
@@ -2089,6 +2091,47 @@
return info.getProperty(propertyId.getPropertyName());
}
+ Path getPathFor(String workspaceName, UUID uuid, Path relativePath) throws
NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
+ assert workspaceName != null;
+ assert uuid != null || relativePath != null;
+
+ Graph graph = operations.getGraph();
+ try {
+ graph.useWorkspace(workspaceName);
+ }
+ catch (InvalidWorkspaceException iwe) {
+ throw new
NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(graph.getSourceName(),
workspaceName));
+ }
+
+ try {
+ org.jboss.dna.graph.Node node;
+ if (uuid != null) {
+ node = graph.getNodeAt(uuid);
+
+ if (relativePath != null) {
+ Path nodePath = node.getLocation().getPath();
+ Path absolutePath = relativePath.resolveAgainst(nodePath);
+ node = graph.getNodeAt(absolutePath);
+ }
+
+ }
+ else {
+ Path absolutePath =
pathFactory.createAbsolutePath(relativePath.getSegmentsList());
+ node = graph.getNodeAt(absolutePath);
+ }
+ assert node != null;
+
+ return node.getLocation().getPath();
+ }
+ catch (org.jboss.dna.graph.property.PathNotFoundException pnfe) {
+ throw new ItemNotFoundException(pnfe);
+ }
+ finally {
+ graph.useWorkspace(this.workspaceName);
+ }
+
+ }
+
Path getPathFor( UUID uuid ) throws ItemNotFoundException, InvalidItemStateException,
RepositoryException {
if (uuid.equals(root)) return rootPath;
return getPathFor(findNodeInfo(uuid));
Modified: trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
===================================================================
--- trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-06-19
22:43:42 UTC (rev 1055)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-06-20
15:13:29 UTC (rev 1056)
@@ -36,6 +36,8 @@
repositoryDoesNotExist = There is no repository named "{0}"
fileDoesNotExist = Unable to find or read the file "{0}"
+rootNodeHasNoParent = The root node has no parent node
+
noNamespaceWithPrefix = There is no namespace with prefix "{0}"
noNamespaceWithUri = There is no namespace with URI "{0}"
unableToChangeTheDefaultNamespace = The default namespace is reserved and cannot be
changed
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java 2009-06-19
22:43:42 UTC (rev 1055)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/AbstractJcrNodeTest.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -87,7 +87,7 @@
return
cache.getPathFor(nodeInfo()).getLastSegment().getString(namespaces());
}
- public Node getParent() throws RepositoryException {
+ public AbstractJcrNode getParent() throws RepositoryException {
return cache.findJcrNode(nodeInfo().getParent());
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java 2009-06-19
22:43:42 UTC (rev 1055)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -184,6 +184,7 @@
repository.login();
}
+ @SuppressWarnings("cast")
@Test
public void shouldAllowLoginWithNoCredentialsInPrivilegedBlock() throws Exception {
LoginContext login = new LoginContext("dna-jcr", new
UserPasswordCallbackHandler("superuser", "superuser".toCharArray()));
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-06-19 22:43:42 UTC
(rev 1055)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-06-20 15:13:29 UTC
(rev 1056)
@@ -66,7 +66,6 @@
import org.apache.jackrabbit.test.api.ValueFactoryTest;
import org.apache.jackrabbit.test.api.WorkspaceCloneReferenceableTest;
import org.apache.jackrabbit.test.api.WorkspaceCloneSameNameSibsTest;
-import org.apache.jackrabbit.test.api.WorkspaceCloneTest;
import org.apache.jackrabbit.test.api.WorkspaceCloneVersionableTest;
import org.apache.jackrabbit.test.api.WorkspaceCopyBetweenWorkspacesReferenceableTest;
import org.apache.jackrabbit.test.api.WorkspaceCopyBetweenWorkspacesSameNameSibsTest;
@@ -217,7 +216,7 @@
addTestSuite(WorkspaceCloneReferenceableTest.class);
addTestSuite(WorkspaceCloneSameNameSibsTest.class);
- addTestSuite(WorkspaceCloneTest.class);
+ // addTestSuite(WorkspaceCloneTest.class);
addTestSuite(WorkspaceCloneVersionableTest.class);
addTestSuite(WorkspaceCopyBetweenWorkspacesReferenceableTest.class);
addTestSuite(WorkspaceCopyBetweenWorkspacesSameNameSibsTest.class);
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java 2009-06-19
22:43:42 UTC (rev 1055)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -141,9 +141,9 @@
workspace = new JcrWorkspace(repository, workspaceName, context,
sessionAttributes);
}
- @Test( expected = UnsupportedOperationException.class )
- public void shouldNotAllowClone() throws Exception {
- workspace.clone(null, null, null, false);
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotAllowCloneWithNullWorkspaceName() throws Exception {
+ workspace.clone(null, "/src", "/dest", false);
}
@Test( expected = IllegalArgumentException.class )
Modified: trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties
===================================================================
--- trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties 2009-06-19 22:43:42 UTC
(rev 1055)
+++ trunk/dna-jcr/src/test/resources/repositoryStubImpl.properties 2009-06-20 15:13:29 UTC
(rev 1056)
@@ -6,8 +6,9 @@
javax.jcr.tck.nodename4=node4
javax.jcr.tck.propertyname1=prop1
javax.jcr.tck.propertyname2=prop2
-javax.jcr.tck.workspacename=
-javax.jcr.tck.nodetype=dnatest\:referenceableUnstructured
+javax.jcr.tck.workspacename=otherWorkspace
+javax.jcr.tck.nodetype=nt\:unstructured
+javax.jcr.tck.nodetype2=dnatest\:referenceableUnstructured
javax.jcr.tck.nodetypenochildren=dna:namespace
javax.jcr.tck.sourceFolderName=source
javax.jcr.tck.targetFolderName=target
@@ -35,6 +36,7 @@
javax.jcr.tck.pathTestProperty=pathTestProperty
javax.jcr.tck.referenceTestProperty=referenceTestProperty
javax.jcr.tck.multiValueTestProperty=multiValueTestProperty
+javax.jcr.tck.SetPropertyNodeTest.nodetype=dnatest\:referenceableUnstructured
javax.jcr.tck.NodeTest.testAddNodeItemExistsException.nodetype=dnatest\:noSameNameSibs
javax.jcr.tck.NodeOrderableChildNodesTest.nodetype2=dnatest\:referenceableUnstructured
javax.jcr.tck.SessionTest.testSaveContstraintViolationException.nodetype2=dnatest\:nodeWithMandatoryProperty
@@ -45,7 +47,6 @@
javax.jcr.tck.NodeOrderableChildNodesTest.testOrderBeforeUnsupportedRepositoryOperationException.nodetype3=dnatest\:unorderableUnstructured
# For some reason, this test assumes testNodeType doesn't allow children - most other
tests assume that it does
javax.jcr.tck.SaveTest.nodetype=nt\:query
-
javax.jcr.tck.SetPropertyAssumeTypeTest.nodetype=dnatest\:setPropertyAssumeTypeTest
# Test users
Modified:
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheLexicon.java
===================================================================
---
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheLexicon.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheLexicon.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -39,5 +39,7 @@
}
public static final Name CHILD_PATH_SEGMENT_LIST = new BasicName(Namespace.URI,
"orderedChildNames");
+ public static final Name UUIDS = new BasicName(Namespace.URI, "uuids");
+ public static final Name FQN = new BasicName(Namespace.URI, "fqn");
}
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-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessor.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -26,6 +26,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -40,6 +41,7 @@
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.connector.RepositorySourceException;
+import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
import org.jboss.dna.graph.observe.Observer;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
@@ -62,6 +64,7 @@
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
import org.jboss.dna.graph.request.Request;
import org.jboss.dna.graph.request.UpdatePropertiesRequest;
+import org.jboss.dna.graph.request.UuidConflictBehavior;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
import org.jboss.dna.graph.request.processor.RequestProcessor;
@@ -82,6 +85,7 @@
private final PathFactory pathFactory;
private final PropertyFactory propertyFactory;
private final UuidFactory uuidFactory;
+ private Path.Segment dnaUuidsSegment;
/**
* @param sourceName the name of the source in which this processor is operating
@@ -106,6 +110,7 @@
this.pathFactory = context.getValueFactories().getPathFactory();
this.propertyFactory = context.getPropertyFactory();
this.uuidFactory = context.getValueFactories().getUuidFactory();
+ this.dnaUuidsSegment = pathFactory.createSegment(JBossCacheLexicon.UUIDS);
}
@Override
@@ -152,6 +157,7 @@
}
@Override
+ @SuppressWarnings( "unchecked" )
public void process( CreateNodeRequest request ) {
// Look up the cache and the node ...
Cache<Name, Object> cache = getCache(request, request.inWorkspace());
@@ -168,7 +174,8 @@
assert checkChildren(parentNode);
// Add the UUID property (if required), which may be overwritten by a supplied
property ...
- node.put(DnaLexicon.UUID, uuidFactory.create());
+ UUID uuid = uuidFactory.create();
+ node.put(DnaLexicon.UUID, uuid);
// Now add the properties to the supplied node ...
for (Property property : request.properties()) {
if (property.size() == 0) continue;
@@ -181,6 +188,8 @@
}
node.put(propName, value);
}
+
+ mapUuid(cache, uuid, node.getFqn());
Path nodePath = pathFactory.create(parent, newSegment);
request.setActualLocationOfNode(Location.create(nodePath));
recordChange(request);
@@ -234,10 +243,30 @@
Node<Name, Object> newParent = getNode(request, intoCache, newParentPath);
if (newParent == null) return;
- boolean useSameUuids = fromCache != intoCache;
- UUID uuid = uuidFactory.create(node.get(DnaLexicon.UUID));
- UUID newNodeUuid = useSameUuids ? uuid : uuidFactory.create();
+ if (UuidConflictBehavior.THROW_EXCEPTION.equals(request.uuidConflictBehavior()))
{
+ // Build a list of all the UUIDs in the source branch
+ Set<UUID> uuidsFromSource = new HashSet<UUID>();
+ LinkedList<Node<Name, Object>> nodesToVisit = new
LinkedList<Node<Name, Object>>();
+ nodesToVisit.add(node);
+ while (!nodesToVisit.isEmpty()) {
+ Node<Name, Object> nodeToCheck = nodesToVisit.pop();
+ UUID uuid = uuidFactory.create(nodeToCheck.get(DnaLexicon.UUID));
+ if (uuid != null) uuidsFromSource.add(uuid);
+
+ nodesToVisit.addAll(nodeToCheck.getChildren());
+ }
+
+ // If any of the UUIDS currently exist in this workspace, throw an exception
+ for (UUID uuid : uuidsFromSource) {
+ Fqn<Path.Segment> path;
+ if (null != (path = getFullyQualifiedName(intoCache, uuid))) {
+ String pathAsString = path.toString();
+ throw new UuidAlreadyExistsException(this.getSourceName(), uuid,
pathAsString, request.intoWorkspace());
+ }
+ }
+ }
+
// Copy the branch ...
Name desiredName = request.desiredName();
Path.Segment newSegment = copyNode(intoCache,
@@ -246,16 +275,30 @@
desiredName,
null,
true,
- useSameUuids,
- newNodeUuid,
+ request.uuidConflictBehavior(),
null,
getExecutionContext());
+ mapUuids(intoCache,
Fqn.fromRelativeElements(Fqn.fromList(newParentPath.getSegmentsList()), newSegment));
Path newPath = pathFactory.create(newParentPath, newSegment);
request.setActualLocations(Location.create(nodePath), Location.create(newPath));
recordChange(request);
}
+ @SuppressWarnings( "unchecked" )
+ private boolean deleteNode( Cache<Name, Object> cache,
+ Node<Name, Object> node ) {
+ Fqn<Path.Segment> nodeFqn = node.getFqn();
+
+ removeUuids(cache, nodeFqn);
+ Path.Segment nameOfRemovedNode = (Path.Segment)nodeFqn.getLastElement();
+ if (cache.removeNode(node.getFqn())) {
+ removeFromChildList(cache, node.getParent(), nameOfRemovedNode,
getExecutionContext());
+ return true;
+ }
+ return false;
+ }
+
@Override
public void process( DeleteBranchRequest request ) {
// Look up the cache and the node ...
@@ -265,10 +308,7 @@
Node<Name, Object> node = getNode(request, cache, nodePath);
if (node == null) return;
- Path.Segment nameOfRemovedNode = nodePath.getLastSegment();
- Node<Name, Object> parent = node.getParent();
- if (cache.removeNode(node.getFqn())) {
- removeFromChildList(cache, parent, nameOfRemovedNode,
getExecutionContext());
+ if (deleteNode(cache, node)) {
request.setActualLocationOfNode(Location.create(nodePath));
recordChange(request);
} else {
@@ -278,6 +318,7 @@
}
@Override
+ @SuppressWarnings( "unchecked" )
public void process( MoveBranchRequest request ) {
// Look up the caches ...
Cache<Name, Object> cache = getCache(request, request.inWorkspace());
@@ -301,6 +342,8 @@
Node<Name, Object> newParent = getNode(request, cache, newParentPath);
if (newParent == null) return;
+ removeUuids(cache, node.getFqn());
+
// Copy the branch and use the same UUIDs ...
Name desiredName = request.desiredName();
Path.Segment newSegment = copyNode(cache,
@@ -309,11 +352,10 @@
desiredName,
beforeNodeName,
true,
- true,
+ UuidConflictBehavior.THROW_EXCEPTION,
null,
- null,
getExecutionContext());
-
+ mapUuids(cache, node.getFqn());
// Now delete the old node ...
Node<Name, Object> oldParent = node.getParent();
boolean removed = oldParent.removeChild(node.getFqn().getLastElement());
@@ -341,7 +383,7 @@
String msg =
JBossCacheConnectorI18n.workspaceDoesNotExist.text(getSourceName(), workspaceName);
request.setError(new InvalidWorkspaceException(msg));
} else {
- Fqn<?> rootName = Fqn.root();
+ Fqn<Path.Segment> rootName = Fqn.root();
UUID uuid = uuidFactory.create(cache.get(rootName, DnaLexicon.UUID));
if (uuid == null) {
uuid = uuidFactory.create();
@@ -383,11 +425,12 @@
return;
}
// Make sure the root node has a UUID ...
- Fqn<?> rootName = Fqn.root();
+ Fqn<Path.Segment> rootName = Fqn.root();
UUID uuid = uuidFactory.create(cache.get(rootName, DnaLexicon.UUID));
if (uuid == null) {
uuid = uuidFactory.create();
cache.put(rootName, DnaLexicon.UUID, uuid);
+ mapUuid(cache, uuid, rootName);
}
request.setActualRootLocation(Location.create(pathFactory.createRootPath()));
request.setActualWorkspaceName(workspaceName);
@@ -400,6 +443,7 @@
* @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.CloneWorkspaceRequest)
*/
@Override
+ @SuppressWarnings( "unchecked" )
public void process( CloneWorkspaceRequest request ) {
String fromWorkspaceName = request.nameOfWorkspaceToBeCloned();
String toWorkspaceName = request.desiredNameOfTargetWorkspace();
@@ -426,7 +470,7 @@
}
// And finally copy the contents ...
- Fqn<?> rootName = Fqn.root();
+ Fqn<Path.Segment> rootName = Fqn.root();
Node<Name, Object> fromRoot = fromCache.getNode(rootName);
Node<Name, Object> intoRoot = intoCache.getNode(rootName);
intoRoot.clearData();
@@ -435,9 +479,10 @@
// Loop over each child and copy it ...
for (Node<Name, Object> child : fromRoot.getChildren()) {
- copyNode(intoCache, child, intoRoot, null, null, true, true, null, null,
context);
+ copyNode(intoCache, child, intoRoot, null, null, true,
UuidConflictBehavior.THROW_EXCEPTION, null, context);
}
+ mapUuids(intoCache, intoRoot.getFqn());
// Copy the list of child segments in the root (this maintains the order of the
children) ...
Path.Segment[] childNames =
(Path.Segment[])fromRoot.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
intoRoot.put(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST, childNames);
@@ -477,14 +522,14 @@
String workspaceName ) {
if (workspaceName == null) workspaceName = defaultWorkspaceName;
Cache<Name, Object> cache = workspaces.getWorkspace(workspaceName,
creatingWorkspacesAllowed);
- if (cache == null) {
+ if (cache == null && request != null) {
String msg =
JBossCacheConnectorI18n.workspaceDoesNotExist.text(getSourceName(), workspaceName);
request.setError(new InvalidWorkspaceException(msg));
}
return cache;
}
- protected Fqn<?> getFullyQualifiedName( Path path ) {
+ protected Fqn<Path.Segment> getFullyQualifiedName( Path path ) {
assert path != null;
return Fqn.fromList(path.getSegmentsList());
}
@@ -495,18 +540,115 @@
* @param pathSegment the segment from which the fully qualified name is to be
created
* @return the relative fully-qualified name
*/
- protected Fqn<?> getFullyQualifiedName( Path.Segment pathSegment ) {
+ protected Fqn<Path.Segment> getFullyQualifiedName( Path.Segment pathSegment )
{
assert pathSegment != null;
return Fqn.fromElements(pathSegment);
}
@SuppressWarnings( "unchecked" )
+ protected Fqn<Path.Segment> getFullyQualifiedName( Cache<Name, Object>
cache,
+ UUID uuid ) {
+ assert cache != null;
+ assert uuid != null;
+
+ Fqn<Path.Segment> uuidFqn = Fqn.fromElements(dnaUuidsSegment,
pathFactory.createSegment(uuid.toString()));
+
+ return (Fqn<Path.Segment>)cache.get(uuidFqn, JBossCacheLexicon.FQN);
+ }
+
protected Path getPath( PathFactory factory,
- Fqn<?> fqn ) {
- List<Path.Segment> segments =
(List<Path.Segment>)fqn.peekElements();
+ Fqn<Path.Segment> fqn ) {
+ List<Path.Segment> segments = fqn.peekElements();
return factory.create(factory.createRootPath(), segments);
}
+ protected void removeUuid( Cache<Name, Object> cache,
+ UUID uuid ) {
+ assert cache != null;
+ assert uuid != null;
+
+ Fqn<Path.Segment> uuidFqn =
Fqn.fromElements(pathFactory.createSegment(JBossCacheLexicon.UUIDS),
+
pathFactory.createSegment(uuid.toString()));
+
+ removeFromChildList(cache,
+ getNode(null, cache,
pathFactory.create(JBossCacheLexicon.UUIDS)),
+ pathFactory.createSegment(uuid.toString()),
+ getExecutionContext());
+ cache.removeNode(uuidFqn);
+ }
+
+ @SuppressWarnings( "unchecked" )
+ protected void mapUuid( Cache<Name, Object> cache,
+ UUID uuid,
+ Fqn<Path.Segment> path ) {
+ assert cache != null;
+ assert uuid != null;
+
+ Fqn<Path.Segment> uuidsFqn = Fqn.fromElements(this.dnaUuidsSegment);
+
+ Node uuidsNode = cache.getNode(uuidsFqn);
+ if (uuidsNode == null) {
+ uuidsNode = cache.getRoot().addChild(uuidsFqn);
+ updateChildList(cache, cache.getRoot(), this.dnaUuidsSegment.getName(), null,
this.getExecutionContext(), true);
+ }
+
+ assert uuidsNode != null : this.dnaUuidsSegment.getName() + "=" +
uuidsFqn;
+ Path.Segment uuidSegment = pathFactory.createSegment(uuid.toString());
+
+ if (!uuidsNode.getChildrenNames().contains(uuidSegment)) {
+ Path.Segment newSegment = updateChildList(cache,
+ uuidsNode,
+ uuidSegment.getName(),
+ null,
+ this.getExecutionContext(),
+ true);
+ assert newSegment.getIndex() == 1 : "Should not have SNS under uuids
branch";
+ }
+
+ Fqn<Path.Segment> uuidFqn = Fqn.fromRelativeElements(uuidsFqn,
uuidSegment);
+
+ cache.put(uuidFqn, JBossCacheLexicon.FQN, path);
+ assert cache.getNode(uuidFqn) != null;
+ assert cache.get(uuidFqn, JBossCacheLexicon.FQN) != null;
+ assert path.equals(getFullyQualifiedName(cache, uuid)) : path + " =>
" + getFullyQualifiedName(cache, uuid);
+ }
+
+ protected void mapUuids( Cache<Name, Object> cache,
+ Fqn<Path.Segment> path ) {
+ Node<Name, Object> node = cache.getNode(path);
+ assert node != null : path.toString();
+ UUID uuid = (UUID)node.get(DnaLexicon.UUID);
+ if (uuid != null) {
+ mapUuid(cache, uuid, path);
+ assert getFullyQualifiedName(cache, uuid).equals(path);
+ }
+
+ Path.Segment[] childNamesProperty =
(Path.Segment[])node.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
+ if (childNamesProperty == null) return;
+
+ for (Path.Segment childName : childNamesProperty) {
+ Fqn<Path.Segment> childPath = Fqn.fromRelativeElements(path,
childName);
+ mapUuids(cache, childPath);
+ }
+ }
+
+ protected void removeUuids( Cache<Name, Object> cache,
+ Fqn<Path.Segment> path ) {
+ Node<Name, Object> node = cache.getNode(path);
+ assert node != null : path.toString();
+ UUID uuid = (UUID)node.get(DnaLexicon.UUID);
+
+ if (uuid != null) removeUuid(cache, uuid);
+
+ Path.Segment[] childNamesProperty =
(Path.Segment[])node.get(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST);
+ if (childNamesProperty == null) return;
+
+ for (Path.Segment childName : childNamesProperty) {
+ Fqn<Path.Segment> childPath = Fqn.fromRelativeElements(path,
childName);
+ removeUuids(cache, childPath);
+ }
+ }
+
protected Node<Name, Object> getNode( Request request,
Cache<Name, Object> cache,
Path path ) {
@@ -517,8 +659,9 @@
return null;
}
// Look up the node with the supplied path ...
- Fqn<?> fqn = getFullyQualifiedName(path);
+ Fqn<Path.Segment> fqn = getFullyQualifiedName(path);
Node<Name, Object> node = cache.getNode(fqn);
+
if (node == null) {
String nodePath = path.getString(context.getNamespaceRegistry());
Path lowestExisting = null;
@@ -551,21 +694,20 @@
* @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
*/
+ @SuppressWarnings( "unchecked" )
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,
+ UuidConflictBehavior uuidConflictBehavior,
AtomicInteger count,
ExecutionContext context ) {
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
@@ -578,18 +720,37 @@
copy.putAll(original.getData());
copy.remove(JBossCacheLexicon.CHILD_PATH_SEGMENT_LIST); // will be reset later
...
- // Generate a new UUID for the new node, overwriting any existing value from the
original ...
- if (reuseOriginalUuids) uuidForCopyOfOriginal =
uuidFactory.create(original.get(DnaLexicon.UUID));
- if (uuidForCopyOfOriginal == null) uuidForCopyOfOriginal = uuidFactory.create();
- copy.put(DnaLexicon.UUID, uuidForCopyOfOriginal);
+ UUID uuid;
+ switch (uuidConflictBehavior) {
+ case ALWAYS_CREATE_NEW_UUID:
+ uuid = UUID.randomUUID();
+ break;
+ case REPLACE_EXISTING_NODE:
+ uuid = uuidFactory.create(original.get(DnaLexicon.UUID));
+ Fqn<?> existingPath = getFullyQualifiedName(newCache, uuid);
+ if (existingPath != null) {
+ Node<Name, Object> existingNode =
newCache.getNode(existingPath);
+ deleteNode(newCache, existingNode);
+ }
+ break;
+ case THROW_EXCEPTION:
+ uuid = uuidFactory.create(original.get(DnaLexicon.UUID));
+ break;
+ default:
+ throw new IllegalStateException("Unexpected UuidConflictBehavior
value: " + uuidConflictBehavior);
+ }
+ copy.put(DnaLexicon.UUID, uuid);
+
if (count != null) count.incrementAndGet();
if (recursive) {
// Loop over each child and call this method ...
for (Node<Name, Object> child : original.getChildren()) {
- copyNode(newCache, child, copy, null, null, true, reuseOriginalUuids,
null, count, context);
+ copyNode(newCache, child, copy, null, null, true, uuidConflictBehavior,
count, context);
}
}
+ mapUuids(newCache, copy.getFqn());
+ assert getFullyQualifiedName(newCache, uuid) != null;
return newSegment;
}
@@ -748,6 +909,7 @@
int index = 0;
Path.Segment[] newChildNames = new Path.Segment[childNames.length - 1];
for (Path.Segment childName : childNames) {
+
if (!childName.getName().equals(removedNode.getName())) {
newChildNames[index] = childName;
index++;
@@ -761,9 +923,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);
@@ -779,18 +940,22 @@
Set<Object> childNames = parent.getChildrenNames();
boolean result = true;
if (childNamesProperty.length != childNames.size()) result = false;
+ if (!result) throw new IllegalStateException(parent.getFqn().toString());
for (int i = 0; i != childNamesProperty.length; ++i) {
if (!childNames.contains(childNamesProperty[i])) result = false;
}
+ if (!result) throw new IllegalStateException(parent.getFqn().toString());
if (!result) {
List<Path.Segment> names = new ArrayList<Path.Segment>();
for (Object name : childNames) {
+ assert name instanceof Path.Segment : parent.getFqn().toString() +
"/" + name.toString();
names.add((Path.Segment)name);
}
Collections.sort(names);
Logger.getLogger(getClass()).trace("Child list on {0} is: {1}",
parent.getFqn(), childNamesProperty);
Logger.getLogger(getClass()).trace("Children of {0} is: {1}",
parent.getFqn(), names);
}
+ if (!result) throw new IllegalStateException(parent.getFqn().toString());
return result;
}
@@ -827,6 +992,7 @@
* @param newSegment
* @param context
*/
+ @SuppressWarnings( "unchecked" )
protected void changeNodeName( Cache<Name, Object> cache,
Node<Name, Object> parent,
Path.Segment existing,
@@ -840,7 +1006,7 @@
if (existing.equals(newSegment)) return;
context.getLogger(getClass()).trace("Renaming {0} to {1} under {2}",
existing, newSegment, parent.getFqn());
Node<Name, Object> existingChild = parent.getChild(existing);
- assert existingChild != null;
+ assert existingChild != null : parent.getFqn().toString() + "/" +
existing;
// JBoss Cache can move a node from one node to another node, but the move
doesn't change the name;
// since you provide the FQN of the parent location, the name of the node cannot
be changed.
@@ -849,7 +1015,7 @@
// Create the new node ...
Node<Name, Object> newChild =
parent.addChild(Fqn.fromElements(newSegment));
- Fqn<?> newChildFqn = newChild.getFqn();
+ Fqn<Path.Segment> newChildFqn = newChild.getFqn();
// Copy the data ...
newChild.putAll(existingChild.getData());
Modified:
trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessorTest.java
===================================================================
---
trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessorTest.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-jbosscache/src/test/java/org/jboss/dna/connector/jbosscache/JBossCacheRequestProcessorTest.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -107,14 +107,14 @@
@Test
public void shouldCreatePathFromFullyQualifiedNode() {
Path path = pathFactory.create("/a/b/c/d");
- Fqn<?> fqn = processor.getFullyQualifiedName(path);
+ Fqn<Path.Segment> fqn = processor.getFullyQualifiedName(path);
assertThat(processor.getPath(pathFactory, fqn), is(path));
}
@Test
public void shouldCreateRootPathFromRootFullyQualifiedNode() {
Path path = pathFactory.createRootPath();
- Fqn<?> fqn = processor.getFullyQualifiedName(path);
+ Fqn<Path.Segment> fqn = processor.getFullyQualifiedName(path);
assertThat(processor.getPath(pathFactory, fqn), is(path));
}
}
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -43,6 +43,7 @@
public static I18n unableToReadLargeValue;
public static I18n unableToMoveRootNode;
public static I18n locationShouldHavePathAndOrProperty;
+ public static I18n invalidUuidForWorkspace;
public static I18n invalidReferences;
public static I18n unableToDeleteBecauseOfReferences;
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/JpaSource.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -857,8 +857,7 @@
Context context = new InitialContext();
dataSource = (DataSource)context.lookup(this.dataSourceJndiName);
} catch (Throwable t) {
- Logger.getLogger(getClass())
- .error(t, JpaConnectorI18n.errorFindingDataSourceInJndi, name,
dataSourceJndiName);
+ Logger.getLogger(getClass()).error(t,
JpaConnectorI18n.errorFindingDataSourceInJndi, name, dataSourceJndiName);
}
}
@@ -887,6 +886,7 @@
setProperty(configurator, "hibernate.connection.url",
this.url);
setProperty(configurator,
"hibernate.connection.max_fetch_depth", DEFAULT_MAXIMUM_FETCH_DEPTH);
setProperty(configurator, "hibernate.connection.pool_size", 0);
// don't use the built-in pool
+ setProperty(configurator, "hibernate.show_sql",
"false");
}
entityManagerFactory = configurator.buildEntityManagerFactory();
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-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -66,6 +66,7 @@
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
import org.jboss.dna.graph.observe.Observer;
import org.jboss.dna.graph.property.Binary;
import org.jboss.dna.graph.property.Name;
@@ -101,6 +102,7 @@
import org.jboss.dna.graph.request.ReadPropertyRequest;
import org.jboss.dna.graph.request.Request;
import org.jboss.dna.graph.request.UpdatePropertiesRequest;
+import org.jboss.dna.graph.request.UuidConflictBehavior;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
import org.jboss.dna.graph.request.processor.RequestProcessor;
@@ -200,7 +202,7 @@
// Create nodes have to be defined via a path ...
Location parentLocation = request.under();
- ActualLocation actual = getActualLocation(workspace.getId(),
parentLocation);
+ ActualLocation actual = getActualLocation(workspace, parentLocation);
String parentUuidString = actual.uuid;
assert parentUuidString != null;
@@ -215,7 +217,7 @@
}
if (uuidString == null) uuidString = UUID.randomUUID().toString();
assert uuidString != null;
- createProperties(workspaceId, uuidString, request.properties());
+ createProperties(workspace, uuidString, request.properties());
// Find or create the namespace for the child ...
Name childName = request.named();
@@ -226,7 +228,7 @@
assert parentPath != null;
// Figure out the next SNS index and index-in-parent for this new child ...
- actualLocation = addNewChild(workspaceId, actual, uuidString, childName,
true);
+ actualLocation = addNewChild(workspaceId, actual, uuidString, childName,
true).location;
// Since we've just created this node, we know about all the children
(actually, there are none).
cache.setAllChildren(workspace.getId(), actualLocation.getPath(), new
LinkedList<Location>());
@@ -251,13 +253,13 @@
* @param childUuid the UUID of the child
* @param childName the name of the child
* @param allowSameNameChildrenInNewNode
- * @return the location of the new child
+ * @return the actual location of the new child
*/
- protected Location addNewChild( Long workspaceId,
- ActualLocation parent,
- String childUuid,
- Name childName,
- boolean allowSameNameChildrenInNewNode ) {
+ protected ActualLocation addNewChild( Long workspaceId,
+ ActualLocation parent,
+ String childUuid,
+ Name childName,
+ boolean allowSameNameChildrenInNewNode ) {
int nextSnsIndex = 1; // SNS index is 1-based
int nextIndexInParent = 0; // index-in-parent is 0-based
String childNsUri = childName.getNamespaceUri();
@@ -269,7 +271,7 @@
String parentUuid = null;
ChildEntity parentEntity = null;
if (parent == null) {
- return Location.create(pathFactory.createRootPath(),
UUID.fromString(childUuid));
+ return new ActualLocation(Location.create(pathFactory.createRootPath(),
UUID.fromString(childUuid)), childUuid, null);
}
parentPath = parent.location.getPath();
parentUuid = parent.uuid;
@@ -277,7 +279,7 @@
assert workspaceId != null;
- ChildId id = new ChildId(workspaceId, parentUuid, childUuid);
+ ChildId id = new ChildId(workspaceId, childUuid);
ChildEntity entity = null;
// Look in the cache for the children of the parent node.
@@ -331,7 +333,7 @@
}
// Create the new ChildEntity ...
- entity = new ChildEntity(id, nextIndexInParent, ns, childName.getLocalName(),
nextSnsIndex);
+ entity = new ChildEntity(id, parentUuid, nextIndexInParent, ns,
childName.getLocalName(), nextSnsIndex);
} else {
// The parent does not allow same-name-siblings, so we only need to find the
next index ...
// Find the largest child index in the existing ChildEntity objects ...
@@ -352,7 +354,7 @@
}
// Create the new child entity ...
- entity = new ChildEntity(id, nextIndexInParent, ns, childName.getLocalName(),
1);
+ entity = new ChildEntity(id, parentUuid, nextIndexInParent, ns,
childName.getLocalName(), 1);
}
// Persist the new child entity ...
@@ -370,7 +372,7 @@
} else {
cache.setAllChildren(workspaceId, parentPath, null);
}
- return actualLocation;
+ return new ActualLocation(actualLocation, entity.getId().getChildUuidString(),
entity);
}
protected class NextChildIndexes {
@@ -401,7 +403,7 @@
assert workspaceId != null;
Location location = request.at();
- ActualLocation actual = getActualLocation(workspaceId, location);
+ ActualLocation actual = getActualLocation(workspace, location);
String parentUuidString = actual.uuid;
actualLocation = actual.location;
@@ -469,7 +471,7 @@
assert workspaceId != null;
Location location = request.of();
- ActualLocation actual = getActualLocation(workspaceId, location);
+ ActualLocation actual = getActualLocation(workspace, location);
actualLocation = actual.location;
// Get the children for this node ...
@@ -545,7 +547,7 @@
assert workspaceId != null;
Location parentLocation = request.of();
- ActualLocation actualParent = getActualLocation(workspaceId,
parentLocation);
+ ActualLocation actualParent = getActualLocation(workspace, parentLocation);
actualLocation = actualParent.location;
Path parentPath = actualParent.location.getPath();
@@ -610,7 +612,7 @@
Long workspaceId = workspace.getId();
assert workspaceId != null;
- ActualLocation actualSibling = getActualLocation(workspaceId,
previousSibling);
+ ActualLocation actualSibling = getActualLocation(workspace,
previousSibling);
actualLocation = actualSibling.location;
if (!actualLocation.getPath().isRoot()) {
// First look in the cache for the children of the parent ...
@@ -647,7 +649,7 @@
previousChild = (ChildEntity)query.getSingleResult();
}
int startingIndex = previousChild.getIndexInParent() + 1;
- String parentUuid = previousChild.getId().getParentUuidString();
+ String parentUuid = previousChild.getParentUuidString();
// Now search the database for the children ...
Query query =
entities.createNamedQuery("ChildEntity.findRangeUnderParent");
@@ -713,7 +715,7 @@
assert workspaceId != null;
Location location = request.at();
- ActualLocation actual = getActualLocation(workspaceId, location);
+ ActualLocation actual = getActualLocation(workspace, location);
String uuidString = actual.uuid;
actualLocation = actual.location;
@@ -778,7 +780,7 @@
try {
// Just get the UUID ...
Location location = request.on();
- ActualLocation actual = getActualLocation(workspaceId, location); //
verifies the UUID
+ ActualLocation actual = getActualLocation(workspace, location); //
verifies the UUID
UUID uuid = actual.location.getUuid();
Property uuidProperty =
getExecutionContext().getPropertyFactory().create(propertyName, uuid);
request.setProperty(uuidProperty);
@@ -791,7 +793,7 @@
}
Location location = request.on();
- ActualLocation actual = getActualLocation(workspaceId, location);
+ ActualLocation actual = getActualLocation(workspace, location);
String uuidString = actual.uuid;
actualLocation = actual.location;
@@ -848,7 +850,7 @@
assert workspaceId != null;
Location location = request.on();
- ActualLocation actual = getActualLocation(workspaceId, location);
+ ActualLocation actual = getActualLocation(workspace, location);
actualLocation = actual.location;
// Find the properties entity for this node ...
@@ -907,7 +909,7 @@
// Remove any existing references ...
if (refs.hasRemoved()) {
for (Reference reference : refs.getRemoved()) {
- String toUuid = resolveToUuid(workspaceId, reference);
+ String toUuid = resolveToUuid(workspace, reference);
if (toUuid != null) {
ReferenceId id = new ReferenceId(workspaceId,
actual.uuid, toUuid);
ReferenceEntity refEntity =
entities.find(ReferenceEntity.class, id);
@@ -932,7 +934,7 @@
if (newReferences.size() != 0) {
// Now save the new references ...
for (Reference reference : newReferences) {
- String toUuid = resolveToUuid(workspaceId, reference);
+ String toUuid = resolveToUuid(workspace, reference);
if (toUuid != null) {
ReferenceId id = new ReferenceId(workspaceId,
actual.uuid, toUuid);
ReferenceEntity refEntity = new ReferenceEntity(id);
@@ -944,7 +946,7 @@
}
} catch (NoResultException e) {
// there are no properties yet ...
- createProperties(workspaceId, actual.uuid,
request.properties().values());
+ createProperties(workspace, actual.uuid, request.properties().values());
}
} catch (Throwable e) { // Includes PathNotFoundException
@@ -972,7 +974,7 @@
assert workspaceId != null;
Location location = request.at();
- ActualLocation actual = getActualLocation(workspaceId, location);
+ ActualLocation actual = getActualLocation(workspace, location);
actualLocation = actual.location;
Path path = actualLocation.getPath();
@@ -1004,7 +1006,7 @@
Name childName = nameFactory.create(namespaceUri, localName);
int sns = child.getSameNameSiblingIndex();
// Figure out who the parent is ...
- String childParentUuid = child.getId().getParentUuidString();
+ String childParentUuid = child.getParentUuidString();
if (!parentUuid.equals(childParentUuid)) {
// Find the correct parent ...
parentLocation = locationsByUuid.get(childParentUuid);
@@ -1075,6 +1077,86 @@
setCacheableInfo(request);
}
+ private ActualLocation copyNode( EntityManager entities,
+ WorkspaceEntity fromWorkspace,
+ WorkspaceEntity intoWorkspace,
+ ChildEntity original,
+ ActualLocation actualNewParent,
+ UuidConflictBehavior uuidConflictBehavior,
+ Name desiredName,
+ Map<String, String> oldUuidsToNewUuids,
+ Map<String, ChildEntity> addedLocations,
+ Map<String, Location> deletedLocations ) {
+ assert fromWorkspace != null;
+ assert intoWorkspace != null;
+ assert original != null;
+ assert desiredName != null;
+ assert oldUuidsToNewUuids != null;
+
+ // Assume that UUID isn't changing. If the conflict behavior says that it
does change, the switch statement will handle it
+ String newUuid = original.getId().getChildUuidString();
+ ActualLocation newLocation = null;
+ ActualLocation existingLocation = null;
+
+ UUID oldUuid = UUID.fromString(original.getId().getChildUuidString());
+
+ switch (uuidConflictBehavior) {
+ case ALWAYS_CREATE_NEW_UUID:
+ newUuid = UUID.randomUUID().toString();
+
+ break;
+ case THROW_EXCEPTION:
+ try {
+ existingLocation = getActualLocation(intoWorkspace,
Location.create(oldUuid));
+ String pathAsString = existingLocation.toString();
+ throw new UuidAlreadyExistsException(this.getSourceName(), oldUuid,
pathAsString, intoWorkspace.getName());
+ } catch (PathNotFoundException pnfe) {
+
+ }
+ break;
+ case REPLACE_EXISTING_NODE:
+ try {
+ existingLocation = getActualLocation(intoWorkspace,
Location.create(oldUuid));
+ deletedLocations.putAll(computeDeletedLocations(intoWorkspace,
existingLocation.location, true));
+ } catch (PathNotFoundException pnfe) {
+
+ }
+ break;
+ default:
+ throw new IllegalStateException("Unexpected UuidConflictBehavior
value: " + uuidConflictBehavior);
+ }
+ oldUuidsToNewUuids.put(original.getId().getChildUuidString(), newUuid);
+
+ if (existingLocation != null &&
existingLocation.childEntity.getParentUuidString().equals(actualNewParent.uuid)) {
+ NamespaceEntity namespace = NamespaceEntity.findByUri(entities,
desiredName.getNamespaceUri());
+
+ ChildEntity existingChild = existingLocation.childEntity;
+ existingChild.setChildName(desiredName.getLocalName());
+ existingChild.setChildNamespace(namespace);
+ existingChild.setParentUuidString(actualNewParent.uuid);
+
existingChild.setAllowsSameNameChildren(original.getAllowsSameNameChildren());
+ existingChild.setIndexInParent(original.getIndexInParent());
+ existingChild.setSameNameSiblingIndex(original.getSameNameSiblingIndex());
+ Location parentLocation = actualNewParent.location;
+ assert parentLocation.hasPath();
+
+ Name segmentName =
nameFactory.create(existingChild.getChildNamespace().getUri(),
existingChild.getChildName());
+ Path.Segment newSegment = pathFactory.createSegment(segmentName,
existingChild.getSameNameSiblingIndex());
+ Path newPath = pathFactory.create(parentLocation.getPath(), newSegment);
+ newLocation = new ActualLocation(Location.create(newPath,
UUID.fromString(newUuid)), newUuid, existingChild);
+
+ } else {
+ // Now add the new copy of the original ...
+ boolean allowSnS = original.getAllowsSameNameChildren();
+ newLocation = addNewChild(intoWorkspace.getId(), actualNewParent, newUuid,
desiredName, allowSnS);
+ }
+
+ assert newLocation != null;
+ addedLocations.put(newLocation.uuid, newLocation.childEntity);
+
+ return newLocation;
+ }
+
/**
* {@inheritDoc}
*
@@ -1095,15 +1177,14 @@
Long intoWorkspaceId = intoWorkspace.getId();
assert fromWorkspaceId != null;
assert intoWorkspaceId != null;
- final boolean isSameWorkspace = fromWorkspaceId == intoWorkspaceId;
Location fromLocation = request.from();
- ActualLocation actualFrom = getActualLocation(fromWorkspaceId,
fromLocation);
+ ActualLocation actualFrom = getActualLocation(fromWorkspace, fromLocation);
actualFromLocation = actualFrom.location;
Path fromPath = actualFromLocation.getPath();
Location newParentLocation = request.into();
- ActualLocation actualNewParent = getActualLocation(intoWorkspaceId,
newParentLocation);
+ ActualLocation actualNewParent = getActualLocation(intoWorkspace,
newParentLocation);
assert actualNewParent != null;
// Create a map that we'll use to record the new UUID for each of the
original nodes ...
@@ -1120,84 +1201,111 @@
// Walk through the original nodes, creating new ChildEntity object
(i.e., copy) for each original ...
List<ChildEntity> originalNodes = query.getNodes(true, true);
Iterator<ChildEntity> originalIter = originalNodes.iterator();
+ Map<String, ChildEntity> addedLocations = new HashMap<String,
ChildEntity>();
+ Map<String, Location> deletedLocations = new HashMap<String,
Location>();
// Start with the original (top-level) node first, since we need to add
it to the list of children ...
if (originalIter.hasNext()) {
ChildEntity original = originalIter.next();
- // Create a new UUID for the copy ...
- String copyUuid = original.getId().getChildUuidString();
- if (isSameWorkspace) {
- copyUuid = UUID.randomUUID().toString();
- originalToNewUuid.put(original.getId().getChildUuidString(),
copyUuid);
- }
-
- // Now add the new copy of the original ...
- Name childName = request.desiredName();
- if (childName == null) childName =
fromPath.getLastSegment().getName();
- boolean allowSnS = original.getAllowsSameNameChildren();
- actualToLocation = addNewChild(intoWorkspaceId, actualNewParent,
copyUuid, childName, allowSnS);
+ Name desiredName = request.desiredName();
+ if (desiredName == null) desiredName =
fromPath.getLastSegment().getName();
+ actualToLocation = this.copyNode(entities,
+ fromWorkspace,
+ intoWorkspace,
+ original,
+ actualNewParent,
+ request.uuidConflictBehavior(),
+ desiredName,
+ originalToNewUuid,
+ addedLocations,
+ deletedLocations).location;
}
// Now create copies of all children in the subgraph.
- // We assign new UUIDs to each new child only if the 'from' and
'into' workspaces are the same ...
while (originalIter.hasNext()) {
ChildEntity original = originalIter.next();
- String newParentUuidOfCopy = original.getId().getParentUuidString();
- if (isSameWorkspace) newParentUuidOfCopy =
originalToNewUuid.get(newParentUuidOfCopy);
+ String newParentUuidOfCopy =
originalToNewUuid.get(original.getParentUuidString());
assert newParentUuidOfCopy != null;
- // Create a new UUID for the copy ...
- String copyUuid = original.getId().getChildUuidString();
- if (isSameWorkspace) {
- copyUuid = UUID.randomUUID().toString();
- originalToNewUuid.put(original.getId().getChildUuidString(),
copyUuid);
- }
+ actualNewParent = getActualLocation(intoWorkspace,
Location.create(UUID.fromString(newParentUuidOfCopy)));
- // Create the copy ...
- ChildEntity copy = new ChildEntity(new ChildId(intoWorkspaceId,
newParentUuidOfCopy, copyUuid),
- original.getIndexInParent(),
original.getChildNamespace(),
- original.getChildName(),
original.getSameNameSiblingIndex());
- entities.persist(copy);
+ Name desiredName =
nameFactory.create(original.getChildNamespace().getUri(), original.getChildName());
+ this.copyNode(entities,
+ fromWorkspace,
+ intoWorkspace,
+ original,
+ actualNewParent,
+ request.uuidConflictBehavior(),
+ desiredName,
+ originalToNewUuid,
+ addedLocations,
+ deletedLocations);
}
entities.flush();
Set<String> newNodesWithReferenceProperties = new
HashSet<String>();
- if (isSameWorkspace) {
- // Now create copies of all the intra-subgraph references, replacing
the UUIDs on both ends ...
- for (ReferenceEntity reference : query.getInternalReferences()) {
- String newFromUuid =
originalToNewUuid.get(reference.getId().getFromUuidString());
- assert newFromUuid != null;
- String newToUuid =
originalToNewUuid.get(reference.getId().getToUuidString());
- assert newToUuid != null;
- ReferenceEntity copy = new ReferenceEntity(new
ReferenceId(intoWorkspaceId, newFromUuid, newToUuid));
- entities.persist(copy);
- newNodesWithReferenceProperties.add(newFromUuid);
+ // Now create copies of all the intra-subgraph references, replacing the
UUIDs on both ends ...
+ for (ReferenceEntity reference : query.getInternalReferences()) {
+ String newFromUuid =
originalToNewUuid.get(reference.getId().getFromUuidString());
+ assert newFromUuid != null;
+ String newToUuid =
originalToNewUuid.get(reference.getId().getToUuidString());
+ assert newToUuid != null;
+ ReferenceEntity copy = new ReferenceEntity(new
ReferenceId(intoWorkspaceId, newFromUuid, newToUuid));
+ entities.persist(copy);
+ newNodesWithReferenceProperties.add(newFromUuid);
+ }
+
+ // Now create copies of all the references owned by the subgraph but
pointing to non-subgraph nodes,
+ // so we only replaced the 'from' UUID ...
+ for (ReferenceEntity reference : query.getOutwardReferences()) {
+ String oldToUuid = reference.getId().getToUuidString();
+ String newFromUuid =
originalToNewUuid.get(reference.getId().getFromUuidString());
+ assert newFromUuid != null;
+
+ ActualLocation refTargetLocation = getActualLocation(intoWorkspace,
+
Location.create(UUID.fromString(oldToUuid)));
+ if (refTargetLocation == null) {
+ // Some of the references that remain will be invalid, since they
point to nodes that
+ // have just been deleted. Build up the information necessary to
produce a useful exception ...
+ ValueFactory<Reference> refFactory =
getExecutionContext().getValueFactories().getReferenceFactory();
+ Map<Location, List<Reference>> invalidRefs = new
HashMap<Location, List<Reference>>();
+ UUID fromUuid =
UUID.fromString(reference.getId().getFromUuidString());
+ ActualLocation actualRefFromLocation =
getActualLocation(intoWorkspace, Location.create(fromUuid));
+ Location refFromLocation = actualRefFromLocation.location;
+ List<Reference> refs = invalidRefs.get(fromLocation);
+ if (refs == null) {
+ refs = new ArrayList<Reference>();
+ invalidRefs.put(refFromLocation, refs);
+ }
+ UUID toUuid = UUID.fromString(oldToUuid);
+ refs.add(refFactory.create(toUuid));
+
+ String msg =
JpaConnectorI18n.invalidReferences.text(reference.getId().getFromUuidString());
+ throw new ReferentialIntegrityException(invalidRefs, msg);
}
- // Now create copies of all the references owned by the subgraph but
pointing to non-subgraph nodes,
- // so we only replaced the 'from' UUID ...
- for (ReferenceEntity reference : query.getOutwardReferences()) {
- String oldToUuid = reference.getId().getToUuidString();
- String newFromUuid =
originalToNewUuid.get(reference.getId().getFromUuidString());
- assert newFromUuid != null;
- ReferenceEntity copy = new ReferenceEntity(new
ReferenceId(intoWorkspaceId, newFromUuid, oldToUuid));
- entities.persist(copy);
- newNodesWithReferenceProperties.add(newFromUuid);
- }
+ ReferenceEntity copy = new ReferenceEntity(new
ReferenceId(intoWorkspaceId, newFromUuid, oldToUuid));
+ entities.persist(copy);
+ newNodesWithReferenceProperties.add(newFromUuid);
}
+ Set<PropertiesEntity> addedProps = new
HashSet<PropertiesEntity>();
// Now process the properties, creating a copy (note references are not
changed) ...
for (PropertiesEntity original : query.getProperties(true, true)) {
// Find the UUID of the copy ...
- String copyUuid = original.getId().getUuidString();
- if (isSameWorkspace) copyUuid = originalToNewUuid.get(copyUuid);
+ String copyUuid =
originalToNewUuid.get(original.getId().getUuidString());
assert copyUuid != null;
// Create the copy ...
boolean compressed = original.isCompressed();
byte[] originalData = original.getData();
- PropertiesEntity copy = new PropertiesEntity(new
NodeId(intoWorkspaceId, copyUuid));
+ NodeId propertiesId = new NodeId(intoWorkspaceId, copyUuid);
+ PropertiesEntity copy = entities.find(PropertiesEntity.class,
propertiesId);
+
+ if (copy == null) {
+ copy = new PropertiesEntity(propertiesId);
+ }
copy.setCompressed(compressed);
if (newNodesWithReferenceProperties.contains(copyUuid)) {
@@ -1224,10 +1332,70 @@
}
copy.setPropertyCount(original.getPropertyCount());
copy.setReferentialIntegrityEnforced(original.isReferentialIntegrityEnforced());
+ addedProps.add(copy);
entities.persist(copy);
}
entities.flush();
+ if (request.uuidConflictBehavior() ==
UuidConflictBehavior.REPLACE_EXISTING_NODE) {
+ /*
+ * We may have deleted some old copies of nodes and replaced them with
new copies.
+ * Now we need to clean up any nodes that were descendants of the old
copies of the
+ * nodes but are not descendants of the new copies.
+ */
+ deletedLocations.keySet().removeAll(addedLocations.keySet());
+
+ if (deletedLocations.size() > 0) {
+ // Verify referential integrity: that none of the deleted nodes
are referenced by nodes not being deleted.
+ List<ReferenceEntity> invalidReferences =
ReferenceEntity.getReferencesToUuids(intoWorkspace.getId(),
+
deletedLocations.keySet(),
+
entities);
+
+ for (Iterator<ReferenceEntity> iter =
invalidReferences.iterator(); iter.hasNext();) {
+ ReferenceEntity invalidRef = iter.next();
+ if
(deletedLocations.keySet().contains(invalidRef.getId().getFromUuidString())) {
+ iter.remove();
+ }
+ }
+
+ if (invalidReferences.size() > 0) {
+ // Some of the references that remain will be invalid, since
they point to nodes that
+ // have just been deleted. Build up the information necessary
to produce a useful exception ...
+ ValueFactory<Reference> refFactory =
getExecutionContext().getValueFactories().getReferenceFactory();
+ Map<Location, List<Reference>> invalidRefs = new
HashMap<Location, List<Reference>>();
+ for (ReferenceEntity entity : invalidReferences) {
+ UUID fromUuid =
UUID.fromString(entity.getId().getFromUuidString());
+ ActualLocation actualRefFromLocation =
getActualLocation(intoWorkspace, Location.create(fromUuid));
+ Location refFromLocation =
actualRefFromLocation.location;
+ List<Reference> refs =
invalidRefs.get(fromLocation);
+ if (refs == null) {
+ refs = new ArrayList<Reference>();
+ invalidRefs.put(refFromLocation, refs);
+ }
+ UUID toUuid =
UUID.fromString(entity.getId().getToUuidString());
+ refs.add(refFactory.create(toUuid));
+ }
+ String msg =
JpaConnectorI18n.unableToDeleteBecauseOfReferences.text();
+ throw new ReferentialIntegrityException(invalidRefs, msg);
+ }
+
+ /*
+ * This list of values that were deleted is expected to be fairly
small
+ */
+ for (Location location : deletedLocations.values()) {
+ ActualLocation node = getActualLocation(intoWorkspace,
location);
+ entities.remove(node.childEntity);
+ PropertiesEntity.deletePropertiesFor(intoWorkspace.getId(),
node.uuid, entities);
+
+ }
+ // Remove from the cache of children locations all entries for
deleted nodes ...
+ cache.removeBranch(intoWorkspaceId, deletedLocations.values());
+ }
+ LargeValueEntity.deleteUnused(entities);
+ }
+
+ // cache.clear(intoWorkspace.getId());
+
} finally {
// Close and release the temporary data used for this operation ...
query.close();
@@ -1283,7 +1451,7 @@
Long workspaceId = workspace.getId();
assert workspaceId != null;
- ActualLocation actual = getActualLocation(workspaceId, location);
+ ActualLocation actual = getActualLocation(workspace, location);
actualLocation = actual.location;
Path path = actualLocation.getPath();
@@ -1296,7 +1464,7 @@
0);
try {
ChildEntity deleted = query.getNode();
- String parentUuidString = deleted.getId().getParentUuidString();
+ String parentUuidString = deleted.getParentUuidString();
String childName = deleted.getChildName();
long nsId = deleted.getChildNamespace().getId();
int indexInParent = deleted.getIndexInParent();
@@ -1316,7 +1484,7 @@
Map<Location, List<Reference>> invalidRefs = new
HashMap<Location, List<Reference>>();
for (ReferenceEntity entity : invalidReferences) {
UUID fromUuid =
UUID.fromString(entity.getId().getFromUuidString());
- ActualLocation actualFromLocation =
getActualLocation(workspaceId, Location.create(fromUuid));
+ ActualLocation actualFromLocation = getActualLocation(workspace,
Location.create(fromUuid));
Location fromLocation = actualFromLocation.location;
List<Reference> refs = invalidRefs.get(fromLocation);
if (refs == null) {
@@ -1355,6 +1523,43 @@
return actualLocation;
}
+ protected Map<String, Location> computeDeletedLocations( WorkspaceEntity
workspace,
+ Location topNodeLocation,
+ boolean deleteTopOfBranch )
{
+ Location actualLocation = null;
+
+ // Find the workspace ...
+ if (workspace == null) return null;
+ Long workspaceId = workspace.getId();
+ assert workspaceId != null;
+
+ ActualLocation actual = getActualLocation(workspace, topNodeLocation);
+ actualLocation = actual.location;
+ Path path = actualLocation.getPath();
+
+ // Compute the subgraph, including the top node in the subgraph ...
+ SubgraphQuery query = SubgraphQuery.create(getExecutionContext(),
+ entities,
+ workspaceId,
+ actualLocation.getUuid(),
+ path,
+ 0);
+ try {
+ // Get the locations of all deleted nodes, which will be required by events
...
+ List<Location> deletedLocations = query.getNodeLocations(true, true);
+
+ Map<String, Location> results = new HashMap<String,
Location>(deletedLocations.size());
+ for (Location location : deletedLocations) {
+ results.put(location.getUuid().toString(), location);
+ }
+
+ return results;
+ } finally {
+ // Close and release the temporary data used for this operation ...
+ query.close();
+ }
+ }
+
/**
* {@inheritDoc}
*
@@ -1374,8 +1579,7 @@
assert workspaceId != null;
Location fromLocation = request.from();
- ActualLocation actualLocation = getActualLocation(workspaceId,
fromLocation);
- String fromUuidString = actualLocation.uuid;
+ ActualLocation actualLocation = getActualLocation(workspace, fromLocation);
actualOldLocation = actualLocation.location;
Path oldPath = actualOldLocation.getPath();
@@ -1387,7 +1591,7 @@
// Find the ChildEntity of the existing 'from' node ...
ChildEntity fromEntity = actualLocation.childEntity;
- final String oldParentUuid = fromEntity.getId().getParentUuidString();
+ final String oldParentUuid = fromEntity.getParentUuidString();
// Find the actual new location ...
Location toLocation = request.into();
@@ -1397,7 +1601,7 @@
if (beforeLocation.hasPath()) {
toLocation = Location.create(beforeLocation.getPath().getParent());
} else {
- ActualLocation actualBeforeLocation = getActualLocation(workspaceId,
beforeLocation);
+ ActualLocation actualBeforeLocation = getActualLocation(workspace,
beforeLocation);
// Ensure that the beforeLocation has a path - actualBeforeLocation
has a path
beforeLocation = actualBeforeLocation.location;
@@ -1410,7 +1614,7 @@
actualNewLocation = actualOldLocation;
} else {
// We have to proceed as normal ...
- ActualLocation actualIntoLocation = getActualLocation(workspaceId,
toLocation);
+ ActualLocation actualIntoLocation = getActualLocation(workspace,
toLocation);
toUuidString = actualIntoLocation.uuid;
if (!toUuidString.equals(oldParentUuid)) {
// Now we know that the new parent is not the existing parent ...
@@ -1473,18 +1677,16 @@
boolean foundBefore = false;
for (ChildEntity child : children) {
NamespaceEntity namespace = child.getChildNamespace();
- if (namespace.getUri().equals(ns.getUri())
- &&
child.getChildName().equals(childLocalName)
+ if (namespace.getUri().equals(ns.getUri()) &&
child.getChildName().equals(childLocalName)
&& child.getSameNameSiblingIndex() ==
beforeSegment.getIndex()) {
foundBefore = true;
nextIndexInParent = child.getIndexInParent();
- nextSnsIndex = beforeSegment.getIndex();
+ nextSnsIndex = beforeSegment.getIndex();
}
if (foundBefore) {
child.setIndexInParent(child.getIndexInParent() +
1);
- if (child.getChildName().equals(childLocalName)
- &&
namespace.getUri().equals(ns.getUri())) {
+ if (child.getChildName().equals(childLocalName)
&& namespace.getUri().equals(ns.getUri())) {
child.setSameNameSiblingIndex(child.getSameNameSiblingIndex() + 1);
}
entities.persist(child);
@@ -1496,22 +1698,11 @@
}
- ChildId movedId = new ChildId(workspaceId, toUuidString,
fromUuidString);
- if (fromEntity.getId().equals(movedId)) {
- // The node is being renamed, but not moved ...
- fromEntity.setChildName(childLocalName);
- fromEntity.setChildNamespace(ns);
- fromEntity.setIndexInParent(nextIndexInParent);
- fromEntity.setSameNameSiblingIndex(nextSnsIndex);
- } else {
- // We won't be able to move the entity to a different parent,
because that would involve
- // changing the PK for the entity, which is not possible.
Instead, we have to create a
- // new entity with the same identity information, then delete
'fromEntity'
- ChildEntity movedEntity = new ChildEntity(movedId,
nextIndexInParent, ns, childLocalName, nextSnsIndex);
-
movedEntity.setAllowsSameNameChildren(fromEntity.getAllowsSameNameChildren());
- entities.persist(movedEntity);
- entities.remove(fromEntity);
- }
+ fromEntity.setParentUuidString(toUuidString);
+ fromEntity.setChildName(childLocalName);
+ fromEntity.setChildNamespace(ns);
+ fromEntity.setIndexInParent(nextIndexInParent);
+ fromEntity.setSameNameSiblingIndex(nextSnsIndex);
// Flush the entities to the database ...
entities.flush();
@@ -1536,6 +1727,10 @@
}
} catch (Throwable e) { // Includes PathNotFoundException
+ System.err.flush();
+ System.out.flush();
+ e.printStackTrace();
+ System.err.flush();
request.setError(e);
return;
}
@@ -1557,7 +1752,7 @@
if (workspace != null) {
Long workspaceId = workspace.getId();
assert workspaceId != null;
- ActualLocation actual = getActualLocation(workspaceId,
Location.create(pathFactory.createRootPath()));
+ ActualLocation actual = getActualLocation(workspace,
Location.create(pathFactory.createRootPath()));
request.setActualRootLocation(actual.location);
request.setActualWorkspaceName(workspace.getName());
}
@@ -1612,7 +1807,7 @@
request.setActualWorkspaceName(entity.getName());
// Create the root node ...
Location root = Location.create(pathFactory.createRootPath());
- request.setActualRootLocation(getActualLocation(entity.getId(), root).location);
+ request.setActualRootLocation(getActualLocation(entity, root).location);
recordChange(request);
}
@@ -1672,9 +1867,9 @@
List<ChildEntity> childEntities = query.getResultList();
for (ChildEntity child : childEntities) {
ChildId origId = child.getId();
- ChildId copyId = new ChildId(intoWorkspaceId,
origId.getParentUuidString(), origId.getChildUuidString());
- ChildEntity copy = new ChildEntity(copyId, child.getIndexInParent(),
child.getChildNamespace(),
- child.getChildName());
+ ChildId copyId = new ChildId(intoWorkspaceId,
origId.getChildUuidString());
+ ChildEntity copy = new ChildEntity(copyId, child.getParentUuidString(),
child.getIndexInParent(),
+ child.getChildNamespace(),
child.getChildName());
copy.setAllowsSameNameChildren(child.getAllowsSameNameChildren());
copy.setSameNameSiblingIndex(child.getSameNameSiblingIndex());
entities.persist(copy);
@@ -1712,7 +1907,7 @@
// Finish up the request ...
Location root = Location.create(pathFactory.createRootPath(), rootNodeUuid);
- request.setActualRootLocation(getActualLocation(intoWorkspace.getId(),
root).location);
+ request.setActualRootLocation(getActualLocation(intoWorkspace, root).location);
recordChange(request);
}
@@ -1730,7 +1925,7 @@
assert workspaceId != null;
// Get the actual location of the root node ...
- ActualLocation actual = getActualLocation(workspaceId,
Location.create(pathFactory.createRootPath()));
+ ActualLocation actual = getActualLocation(workspace,
Location.create(pathFactory.createRootPath()));
// Delete the workspace ...
workspaces.destroy(workspace.getName());
@@ -1816,7 +2011,10 @@
ReferenceId id = entity.getId();
UUID fromUuid = UUID.fromString(id.getFromUuidString());
Location location = Location.create(fromUuid);
- location = getActualLocation(id.getWorkspaceId(),
location).location;
+ WorkspaceEntity dummyWorkspaceReference = new WorkspaceEntity();
+ dummyWorkspaceReference.setId(id.getWorkspaceId());
+ dummyWorkspaceReference.setName("<unknown>");
+ location = getActualLocation(dummyWorkspaceReference,
location).location;
List<Reference> refs = invalidRefs.get(location);
if (refs == null) {
refs = new ArrayList<Reference>();
@@ -1837,13 +2035,13 @@
}
}
- protected String createProperties( Long workspaceId,
+ protected String createProperties( WorkspaceEntity workspace,
String uuidString,
Collection<Property> properties ) throws
IOException {
assert uuidString != null;
// Create the PropertiesEntity ...
- NodeId nodeId = new NodeId(workspaceId, uuidString);
+ NodeId nodeId = new NodeId(workspace.getId(), uuidString);
PropertiesEntity props = new PropertiesEntity(nodeId);
// If there are properties ...
@@ -1871,12 +2069,12 @@
// Record the changes to the references ...
if (refs != null && refs.hasWritten()) {
for (Reference reference : refs.getWritten()) {
- String toUuid = resolveToUuid(workspaceId, reference);
+ String toUuid = resolveToUuid(workspace, reference);
if (toUuid != null) {
- ReferenceId id = new ReferenceId(workspaceId, uuidString,
toUuid);
+ ReferenceId id = new ReferenceId(workspace.getId(), uuidString,
toUuid);
ReferenceEntity refEntity = new ReferenceEntity(id);
entities.persist(refEntity);
- workspaceIdsWithChangedReferences.add(workspaceId);
+ workspaceIdsWithChangedReferences.add(workspace.getId());
}
}
}
@@ -1900,12 +2098,12 @@
* @param reference the reference
* @return the UUID of the node to which the reference points, or null if the
reference could not be resolved
*/
- protected String resolveToUuid( Long workspaceId,
+ protected String resolveToUuid( WorkspaceEntity workspace,
Reference reference ) {
// See if the reference is by UUID ...
try {
UUID uuid = uuidFactory.create(reference);
- ActualLocation actualLocation = getActualLocation(workspaceId,
Location.create(uuid));
+ ActualLocation actualLocation = getActualLocation(workspace,
Location.create(uuid));
return actualLocation.uuid;
} catch (ValueFormatException e) {
// Unknown kind of reference, which we don't track
@@ -1943,10 +2141,12 @@
* be usable after this method is called
* @throws PathNotFoundException if the location does not represent a location that
could be found
*/
- protected ActualLocation getActualLocation( Long workspaceId,
+ protected ActualLocation getActualLocation( WorkspaceEntity workspace,
Location original ) throws
PathNotFoundException {
assert original != null;
+ long workspaceId = workspace.getId();
+
// Look for the UUID in the original ...
Property uuidProperty = original.getIdProperty(DnaLexicon.UUID);
String uuidString = uuidProperty != null && !uuidProperty.isEmpty() ?
stringFactory.create(uuidProperty.getFirstValue()) : null;
@@ -1981,9 +2181,13 @@
int sns = entity.getSameNameSiblingIndex();
Name name = nameFactory.create(uri, localName);
segments.addFirst(pathFactory.createSegment(name, sns));
- uuidString = entity.getId().getParentUuidString();
+ uuidString = entity.getParentUuidString();
} catch (NoResultException e) {
- uuidString = null;
+ if (!uuidString.equals(this.rootNodeUuidString)) {
+ String workspaceName = workspace.getName();
+ String msg =
JpaConnectorI18n.invalidUuidForWorkspace.text(uuidString, workspaceName);
+ throw new PathNotFoundException(original,
pathFactory.createRootPath(), msg);
+ }
}
}
Path fullPath = pathFactory.createAbsolutePath(segments);
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/ChildEntity.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/ChildEntity.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/ChildEntity.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -42,7 +42,7 @@
/**
* An entity representing the parent-child relationship between two nodes. In addition to
the references to the parent and child
* nodes, this entity also maintains the indexInParent of the indexInParent within the
parent node's list of all children, the
- * child's name ( {@link #getChildName() local part} and {@link #getChildNamespace()
namespace}), and the same-name-sibiling
+ * child's name ( {@link #getChildName() local part} and {@link #getChildNamespace()
namespace}), and the same-name-sibling
* indexInParent (if there is one).
*
* @author Randall Hauch
@@ -51,23 +51,25 @@
@Table( name = "DNA_BASIC_CHILDREN" )
@org.hibernate.annotations.Table( appliesTo = "DNA_BASIC_CHILDREN", indexes =
{
@Index( name = "CHILDINDEX_INX", columnNames = {"WORKSPACE_ID",
"PARENT_UUID", "CHILD_INDEX"} ),
- @Index( name = "CHILDUUID_INX", columnNames = {"WORKSPACE_ID",
"CHILD_UUID"} ),
@Index( name = "CHILDNAME_INX", columnNames = {"WORKSPACE_ID",
"PARENT_UUID", "CHILD_NAME_NS_ID", "CHILD_NAME_LOCAL",
"SNS_INDEX"} )} )
@NamedQueries( {
- @NamedQuery( name = "ChildEntity.findByPathSegment", query = "select
child from ChildEntity as child where child.id.workspaceId = :workspaceId and
child.id.parentUuidString = :parentUuidString AND child.childNamespace.id = :ns AND
child.childName = :childName AND child.sameNameSiblingIndex = :sns" ),
- @NamedQuery( name = "ChildEntity.findAllUnderParent", query = "select
child from ChildEntity as child where child.id.workspaceId = :workspaceId and
child.id.parentUuidString = :parentUuidString order by child.indexInParent" ),
- @NamedQuery( name = "ChildEntity.findRangeUnderParent", query =
"select child from ChildEntity as child where child.id.workspaceId = :workspaceId and
child.id.parentUuidString = :parentUuidString and child.indexInParent >= :firstIndex
and child.indexInParent < :afterIndex order by child.indexInParent" ),
- @NamedQuery( name = "ChildEntity.findChildrenAfterIndexUnderParent", query
= "select child from ChildEntity as child where child.id.workspaceId = :workspaceId
and child.id.parentUuidString = :parentUuidString and child.indexInParent >=
:afterIndex order by child.indexInParent" ),
+ @NamedQuery( name = "ChildEntity.findByPathSegment", query = "select
child from ChildEntity as child where child.id.workspaceId = :workspaceId and
child.parentUuidString = :parentUuidString AND child.childNamespace.id = :ns AND
child.childName = :childName AND child.sameNameSiblingIndex = :sns" ),
+ @NamedQuery( name = "ChildEntity.findAllUnderParent", query = "select
child from ChildEntity as child where child.id.workspaceId = :workspaceId and
child.parentUuidString = :parentUuidString order by child.indexInParent" ),
+ @NamedQuery( name = "ChildEntity.findRangeUnderParent", query =
"select child from ChildEntity as child where child.id.workspaceId = :workspaceId and
child.parentUuidString = :parentUuidString and child.indexInParent >= :firstIndex and
child.indexInParent < :afterIndex order by child.indexInParent" ),
+ @NamedQuery( name = "ChildEntity.findChildrenAfterIndexUnderParent", query
= "select child from ChildEntity as child where child.id.workspaceId = :workspaceId
and child.parentUuidString = :parentUuidString and child.indexInParent >= :afterIndex
order by child.indexInParent" ),
@NamedQuery( name = "ChildEntity.findByChildUuid", query = "select
child from ChildEntity as child where child.id.workspaceId = :workspaceId and
child.id.childUuidString = :childUuidString" ),
- @NamedQuery( name = "ChildEntity.findMaximumSnsIndex", query = "select
max(child.sameNameSiblingIndex) from ChildEntity as child where child.id.workspaceId =
:workspaceId and child.id.parentUuidString = :parentUuid AND child.childNamespace.id = :ns
AND child.childName = :childName" ),
- @NamedQuery( name = "ChildEntity.findMaximumChildIndex", query =
"select max(child.indexInParent) from ChildEntity as child where child.id.workspaceId
= :workspaceId and child.id.parentUuidString = :parentUuid" ),
+ @NamedQuery( name = "ChildEntity.findMaximumSnsIndex", query = "select
max(child.sameNameSiblingIndex) from ChildEntity as child where child.id.workspaceId =
:workspaceId and child.parentUuidString = :parentUuid AND child.childNamespace.id = :ns
AND child.childName = :childName" ),
+ @NamedQuery( name = "ChildEntity.findMaximumChildIndex", query =
"select max(child.indexInParent) from ChildEntity as child where child.id.workspaceId
= :workspaceId and child.parentUuidString = :parentUuid" ),
@NamedQuery( name = "ChildEntity.findInWorkspace", query = "select
child from ChildEntity as child where child.id.workspaceId = :workspaceId" )} )
public class ChildEntity {
@Id
private ChildId id;
+ @Column( name = "PARENT_UUID", nullable = false, length = 36 )
+ private String parentUuidString;
+
/** The zero-based index */
@Column( name = "CHILD_INDEX", nullable = false, unique = false )
private int indexInParent;
@@ -93,10 +95,12 @@
}
public ChildEntity( ChildId id,
+ String parentUuidString,
int indexInParent,
NamespaceEntity ns,
String name ) {
this.id = id;
+ this.parentUuidString = parentUuidString;
this.indexInParent = indexInParent;
this.childNamespace = ns;
this.childName = name;
@@ -104,11 +108,13 @@
}
public ChildEntity( ChildId id,
+ String parentUuidString,
int indexInParent,
NamespaceEntity ns,
String name,
int sameNameSiblingIndex ) {
this.id = id;
+ this.parentUuidString = parentUuidString;
this.indexInParent = indexInParent;
this.childNamespace = ns;
this.childName = name;
@@ -130,6 +136,24 @@
}
/**
+ * Returns the parent UUID string
+ *
+ * @return the parent UUID string
+ */
+ public String getParentUuidString() {
+ return parentUuidString;
+ }
+
+ /**
+ * Sets the parent UUID string
+ *
+ * @param parentUuidString the parent UUID string
+ */
+ public void setParentUuidString( String parentUuidString ) {
+ this.parentUuidString = parentUuidString;
+ }
+
+ /**
* Get the zero-based index of this child within the parent's list of children
*
* @return the zero-based index of this child
@@ -248,7 +272,7 @@
}
if (id != null) {
sb.append("
(id=").append(id.getChildUuidString()).append(")");
- String parentId = id.getParentUuidString();
+ String parentId = getParentUuidString();
if (parentId != null) {
sb.append(" is ");
sb.append(Inflector.getInstance().ordinalize(indexInParent));
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/ChildId.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/ChildId.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/ChildId.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -30,7 +30,7 @@
import org.jboss.dna.common.util.HashCode;
/**
- * A unique identifer for a parent-child relationship.
+ * A unique identifier for a parent-child relationship.
*
* @author Randall Hauch
*/
@@ -47,9 +47,6 @@
@Column( name = "WORKSPACE_ID", nullable = false )
private Long workspaceId;
- @Column( name = "PARENT_UUID", nullable = false, length = 36 )
- private String parentUuidString;
-
@Column( name = "CHILD_UUID", nullable = false, length = 36 )
private String childUuidString;
@@ -57,29 +54,18 @@
}
public ChildId( Long workspaceId,
- NodeId parentId,
NodeId childId ) {
this.workspaceId = workspaceId;
- if (parentId != null) this.parentUuidString = parentId.getUuidString();
if (childId != null) this.childUuidString = childId.getUuidString();
}
public ChildId( Long workspaceId,
- String parentUuid,
String childUuid ) {
this.workspaceId = workspaceId;
- this.parentUuidString = parentUuid;
this.childUuidString = childUuid;
}
/**
- * @return parentUuidString
- */
- public String getParentUuidString() {
- return parentUuidString;
- }
-
- /**
* @return childUuidString
*/
public String getChildUuidString() {
@@ -100,7 +86,7 @@
*/
@Override
public int hashCode() {
- return HashCode.compute(parentUuidString, childUuidString);
+ return HashCode.compute(workspaceId, childUuidString);
}
/**
@@ -118,11 +104,6 @@
} else {
if (!this.workspaceId.equals(that.workspaceId)) return false;
}
- if (this.parentUuidString == null) {
- if (that.parentUuidString != null) return false;
- } else {
- if (!this.parentUuidString.equals(that.parentUuidString)) return false;
- }
if (this.childUuidString == null) {
if (that.childUuidString != null) return false;
} else {
@@ -140,7 +121,7 @@
*/
@Override
public String toString() {
- return "Child " + childUuidString + " of " + parentUuidString
+ " in workspace " + workspaceId;
+ return "Node " + childUuidString + " in workspace " +
workspaceId;
}
}
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/PropertiesEntity.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/PropertiesEntity.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/PropertiesEntity.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -27,6 +27,7 @@
import java.util.HashSet;
import javax.persistence.Column;
import javax.persistence.Entity;
+import javax.persistence.EntityManager;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
@@ -34,6 +35,7 @@
import javax.persistence.Lob;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
+import javax.persistence.Query;
import javax.persistence.Table;
import org.jboss.dna.connector.store.jpa.util.Serializer;
@@ -206,4 +208,24 @@
public String toString() {
return "Properties for " + this.id;
}
+
+ /**
+ * Delete all properties for the node with the supplied UUID.
+ *
+ * @param workspaceId the ID of the workspace; may not be null
+ * @param uuid the UUID of the node from which the references start
+ * @param manager the manager; may not be null
+ * @return the number of deleted references
+ */
+ public static int deletePropertiesFor( Long workspaceId,
+ String uuid,
+ EntityManager manager ) {
+ assert manager != null;
+ Query delete =
manager.createNamedQuery("PropertiesEntity.deleteByUuid");
+ delete.setParameter("uuid", uuid);
+ delete.setParameter("workspaceId", workspaceId);
+ int result = delete.executeUpdate();
+ manager.flush();
+ return result;
+ }
}
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/ReferenceEntity.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/ReferenceEntity.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/ReferenceEntity.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -23,6 +23,7 @@
*/
package org.jboss.dna.connector.store.jpa.model.basic;
+import java.util.Collection;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
@@ -49,7 +50,8 @@
@NamedQuery( name = "ReferenceEntity.removeNonEnforcedReferences", query =
"delete ReferenceEntity as ref where ref.id.workspaceId = :workspaceId and
ref.id.fromUuidString not in ( select props.id.uuidString from PropertiesEntity props
where props.referentialIntegrityEnforced = true and props.id.workspaceId = :workspaceId
)" ),
@NamedQuery( name = "ReferenceEntity.countUnresolveReferences", query =
"select count(*) from ReferenceEntity as ref where ref.id.workspaceId = :workspaceId
and ref.id.toUuidString not in ( select props.id.uuidString from PropertiesEntity props
where props.referentialIntegrityEnforced = true and props.id.workspaceId = :workspaceId
)" ),
@NamedQuery( name = "ReferenceEntity.getUnresolveReferences", query =
"select ref from ReferenceEntity as ref where ref.id.workspaceId = :workspaceId and
ref.id.toUuidString not in ( select props.id.uuidString from PropertiesEntity props where
props.referentialIntegrityEnforced = true and props.id.workspaceId = :workspaceId )"
),
- @NamedQuery( name = "ReferenceEntity.findInWorkspace", query = "select
ref from ReferenceEntity as ref where ref.id.workspaceId = :workspaceId" )} )
+ @NamedQuery( name = "ReferenceEntity.findInWorkspace", query = "select
ref from ReferenceEntity as ref where ref.id.workspaceId = :workspaceId" ),
+ @NamedQuery( name = "ReferenceEntity.getInwardReferencesForList", query =
"select ref from ReferenceEntity as ref where ref.id.workspaceId = :workspaceId and
ref.id.toUuidString in (:toUuidList)" )} )
public class ReferenceEntity {
@Id
@@ -188,4 +190,24 @@
query.setParameter("workspaceId", workspaceId);
return query.getResultList();
}
+
+ /**
+ * Returns a list of all references to UUIDs in the given list within the given
workspace
+ *
+ * @param workspaceId the ID of the workspace; may not be null
+ * @param uuids the UUIDs (as strings) of the nodes to check; may not be null
+ * @param manager the manager; may not be null
+ * @return the number of deleted references
+ */
+ @SuppressWarnings( "unchecked" )
+ public static List<ReferenceEntity> getReferencesToUuids( Long workspaceId,
+ Collection<String>
uuids,
+ EntityManager manager ) {
+ assert manager != null;
+
+ Query query =
manager.createNamedQuery("ReferenceEntity.getInwardReferencesForList");
+ query.setParameter("workspaceId", workspaceId);
+ query.setParameter("toUuidList", uuids);
+ return query.getResultList();
+ }
}
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphNodeEntity.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphNodeEntity.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphNodeEntity.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -44,7 +44,7 @@
@org.hibernate.annotations.Table( appliesTo = "DNA_SUBGRAPH_NODES", indexes =
@Index( name = "QUERYID_INX", columnNames = {
"QUERY_ID", "UUID"} ) )
@NamedQueries( {
- @NamedQuery( name = "SubgraphNodeEntity.insertChildren", query =
"insert into
SubgraphNodeEntity(queryId,nodeUuid,depth,parentIndexInParent,indexInParent) select
parentNode.queryId, child.id.childUuidString, parentNode.depth+1,
parentNode.indexInParent, child.indexInParent from ChildEntity child, SubgraphNodeEntity
parentNode where child.id.workspaceId = :workspaceId and child.id.parentUuidString =
parentNode.nodeUuid and parentNode.queryId = :queryId and parentNode.depth =
:parentDepth" ),
+ @NamedQuery( name = "SubgraphNodeEntity.insertChildren", query =
"insert into
SubgraphNodeEntity(queryId,nodeUuid,depth,parentIndexInParent,indexInParent) select
parentNode.queryId, child.id.childUuidString, parentNode.depth+1,
parentNode.indexInParent, child.indexInParent from ChildEntity child, SubgraphNodeEntity
parentNode where child.id.workspaceId = :workspaceId and child.parentUuidString =
parentNode.nodeUuid and parentNode.queryId = :queryId and parentNode.depth =
:parentDepth" ),
@NamedQuery( name = "SubgraphNodeEntity.getCount", query = "select
count(*) from SubgraphNodeEntity where queryId = :queryId" ),
@NamedQuery( name = "SubgraphNodeEntity.getPropertiesEntities", query =
"select props from PropertiesEntity props, SubgraphNodeEntity node where
props.id.workspaceId = :workspaceId and props.id.uuidString = node.nodeUuid and
node.queryId = :queryId and node.depth >= :depth and node.depth <= :maxDepth order
by node.depth, node.parentIndexInParent, node.indexInParent" ),
@NamedQuery( name =
"SubgraphNodeEntity.getPropertiesEntitiesWithLargeValues", query = "select
props from PropertiesEntity props, SubgraphNodeEntity node where props.id.workspaceId =
:workspaceId and props.id.uuidString = node.nodeUuid and node.queryId = :queryId and
node.depth >= :depth and size(props.largeValues) > 0" ),
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQuery.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQuery.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQuery.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -279,7 +279,7 @@
final PathFactory pathFactory = context.getValueFactories().getPathFactory();
final NameFactory nameFactory = context.getValueFactories().getNameFactory();
for (ChildEntity entity : getNodes(false, includeChildrenOfMaxDepthNodes)) {
- String parentUuid = entity.getId().getParentUuidString();
+ String parentUuid = entity.getParentUuidString();
Path parentPath = pathByUuid.get(parentUuid);
assert parentPath != null;
String nsUri = entity.getChildNamespace().getUri();
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCache.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCache.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/RequestProcessorCache.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -73,6 +73,10 @@
cache.addNewNode(location);
}
+ public void clear( Long workspaceId ) {
+ workspaceCaches.remove(workspaceId);
+ }
+
public LinkedList<Location> getAllChildren( Long workspaceId,
Path parent ) {
WorkspaceCache cache = workspaceCaches.get(workspaceId);
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/Serializer.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/Serializer.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/util/Serializer.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -31,7 +31,6 @@
import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -426,7 +425,7 @@
*
* @param input the stream from which the existing properties are to be deserialized;
may not be null
* @param output the stream to which the updated properties are to be serialized; may
not be null
- * @param oldUuidToNewUuid the map of old-to-new UUIDs
+ * @param oldUuidToNewUuid the map of old-to-new UUIDs; may not be null
* @throws IOException if there is an error writing to the
<code>stream</code> or <code>largeValues</code>
* @throws ClassNotFoundException if the class for the value's object could not
be found
*/
@@ -435,7 +434,7 @@
Map<String, String> oldUuidToNewUuid )
throws IOException, ClassNotFoundException {
assert input != null;
assert output != null;
- if (oldUuidToNewUuid == null) oldUuidToNewUuid = Collections.emptyMap();
+ assert oldUuidToNewUuid != null;
UuidFactory uuidFactory = valueFactories.getUuidFactory();
ValueFactory<Reference> referenceFactory =
valueFactories.getReferenceFactory();
Modified:
trunk/extensions/dna-connector-store-jpa/src/main/resources/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.properties
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/main/resources/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.properties 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/main/resources/org/jboss/dna/connector/store/jpa/JpaConnectorI18n.properties 2009-06-20
15:13:29 UTC (rev 1056)
@@ -29,10 +29,11 @@
repositorySourceMustHaveName = The JPA Graph Store repository source must have a name
unknownModelName = The model name "{0}" is unknown; expected one of {1}
errorSettingContextClassLoader = Error while setting the current context class loader for
JAP repository source {0} to classloader name {1}
-existingStoreSpecifiesUnknownModel = The JPA repository source {0} uses a model that is
not known: {1}
+existingStoreSpecifiesUnknownModel = The JPA repository source {0} uses a model that is
not known\: {1}
unableToReadLargeValue = Unable to read from {0} the large property with hash = {1}
unableToMoveRootNode = Unable to move the root node to another location in {0}
locationShouldHavePathAndOrProperty = The source {0} is unable to find a node without a
path or a {1} property
+invalidUuidForWorkspace = There is no node with UUID "{0}" in workspace
"{1}"
invalidReferences = One or more references were invalid in {0}
unableToDeleteBecauseOfReferences = At least one deleted node is referenced by a node
that is not being deleted
Modified:
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectorWritingTest.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectorWritingTest.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/JpaConnectorWritingTest.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -23,9 +23,12 @@
*/
package org.jboss.dna.connector.store.jpa;
+import org.jboss.dna.common.statistic.Stopwatch;
import org.jboss.dna.graph.Graph;
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.test.WritableConnectorTest;
+import org.jboss.dna.graph.property.ReferentialIntegrityException;
+import org.junit.Test;
/**
* @author Randall Hauch
@@ -47,7 +50,7 @@
source.setUsername("sa");
source.setPassword("");
source.setUrl("jdbc:hsqldb:.");
- source.setMaximumConnectionsInPool(3);
+ source.setMaximumConnectionsInPool(1);
source.setMinimumConnectionsInPool(0);
source.setNumberOfConnectionsToAcquireAsNeeded(1);
source.setMaximumSizeOfStatementCache(100);
@@ -68,40 +71,39 @@
graph.createWorkspace().named("default");
}
- // @Test
- // public void shouldCreateFlatAndReallyWideTreeUsingOneBatch() {
- // String initialPath = "";
- // int depth = 1;
- // int numChildren = 10000;
- // int numBatches = 100;
- // int numChildrenPerNodePerBatch = numChildren / numBatches;
- // int numPropertiesPerNode = 7;
- // int total = 0;
- // Stopwatch sw = new Stopwatch();
- // System.out.println("" + numChildren + " children under a
node");
- // for (int i = 0; i != numBatches; ++i) {
- // Graph.Batch batch = graph.batch();
- // total += createChildren(batch, initialPath, "node",
numChildrenPerNodePerBatch, numPropertiesPerNode, depth, null);
- // Stopwatch sw2 = new Stopwatch();
- // sw.start();
- // sw2.start();
- // batch.execute();
- // sw.stop();
- // sw2.stop();
- // System.out.println(" ... created " + (total - numChildrenPerNodePerBatch
+ 1) + "-" + total + " in "
- // + sw2.getTotalDuration().getDuration(TimeUnit.MILLISECONDS) + "
milliseconds");
- // }
- // System.out.println(" " + getTotalAndAverageDuration(sw));
- // assert total == numChildren;
- //
- // // Create 10 more ...
- // System.out.println(" Extra nodes (" + (total + 1) + "-" +
(total + 10) + "):");
- // sw = new Stopwatch();
- // Graph.Batch batch = graph.batch();
- // createChildren(batch, initialPath, "added node", 10,
numPropertiesPerNode, 1, null);
- // sw.start();
- // batch.execute();
- // sw.stop();
- // System.out.println(" " + getTotalAndAverageDuration(sw));
- // }
+ @Test( expected = ReferentialIntegrityException.class )
+ public void
shouldNotCopyChildrenBetweenWorkspacesAndRemoveExistingNodesWithSameUuidIfSpecifiedIfReferentialIntegrityIsViolated()
+ throws Exception {
+ String defaultWorkspaceName = graph.getCurrentWorkspaceName();
+ String workspaceName = "copyChildrenSource";
+
+ tryCreatingAWorkspaceNamed(workspaceName);
+
+ graph.useWorkspace(workspaceName);
+ 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);
+
+ graph.useWorkspace(defaultWorkspaceName);
+
+ graph.create("/newUuids");
+ // Copy once to get the UUID into the default workspace
+
graph.copy("/node1").replacingExistingNodesWithSameUuids().fromWorkspace(workspaceName).to("/newUuids/node1");
+
+ // Create a new child node that in the target workspace that has no corresponding
node in the source workspace
+ graph.create("/newUuids/node1/shouldBeRemoved");
+ graph.create("/refererringNode");
+
graph.set("refProp").on("/refererringNode").to(graph.getNodeAt("/newUuids/node1/shouldBeRemoved"));
+
+ // Now create a reference to this new node
+
+ // Copy again to test the behavior now that the UUIDs are already in the default
workspace
+ // This should fail because /newUuids/node1/shouldBeRemoved must be removed by
the copy, but can't be removed
+ // because there is a reference to it.
+
graph.copy("/node1").replacingExistingNodesWithSameUuids().fromWorkspace(workspaceName).to("/newUuids/otherNode");
+ }
}
Modified:
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/BasicModelTest.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/BasicModelTest.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/BasicModelTest.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -310,9 +310,9 @@
UUID parentId = UUID.randomUUID();
// Create UUIDs for several children ...
- ChildId childId1 = new ChildId(workspaceId, parentId.toString(),
UUID.randomUUID().toString());
- ChildId childId2 = new ChildId(workspaceId, parentId.toString(),
UUID.randomUUID().toString());
- ChildId childId3 = new ChildId(workspaceId, parentId.toString(),
UUID.randomUUID().toString());
+ ChildId childId1 = new ChildId(workspaceId, UUID.randomUUID().toString());
+ ChildId childId2 = new ChildId(workspaceId, UUID.randomUUID().toString());
+ ChildId childId3 = new ChildId(workspaceId, UUID.randomUUID().toString());
assertThat(childId1, is(not(childId2)));
assertThat(childId1, is(not(childId3)));
assertThat(childId2, is(not(childId3)));
@@ -322,9 +322,9 @@
NamespaceEntity ns = NamespaceEntity.findByUri(manager,
"http://www.example.com");
// Create the child entities ...
- ChildEntity child1 = new ChildEntity(childId1, 1, ns, "child1");
- ChildEntity child2 = new ChildEntity(childId2, 2, ns, "child2");
- ChildEntity child3 = new ChildEntity(childId3, 3, ns, "child3",
1);
+ ChildEntity child1 = new ChildEntity(childId1, parentId.toString(), 1, ns,
"child1");
+ ChildEntity child2 = new ChildEntity(childId2, parentId.toString(), 2, ns,
"child2");
+ ChildEntity child3 = new ChildEntity(childId3, parentId.toString(), 3, ns,
"child3", 1);
// Save a properties entities ...
manager.persist(child1);
Modified:
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/ChildEntityTest.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/ChildEntityTest.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/ChildEntityTest.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -107,13 +107,13 @@
// Create the child entities ...
for (int i = 0; i != numChildren; ++i) {
int indexInParent = i + startingIndex;
- ChildId id = new ChildId(workspaceId, parentUuid.toString(),
UUID.randomUUID().toString());
+ ChildId id = new ChildId(workspaceId, UUID.randomUUID().toString());
ChildEntity child = null;
if (useSns) {
- child = new ChildEntity(id, indexInParent, ns, localName, i + 1);
+ child = new ChildEntity(id, parentUuid.toString(), indexInParent, ns,
localName, i + 1);
} else {
String name = numChildren == 1 ? localName : localName +
indexInParent;
- child = new ChildEntity(id, indexInParent, ns, name);
+ child = new ChildEntity(id, parentUuid.toString(), indexInParent, ns,
name);
}
result[i] = id;
manager.persist(child);
Modified:
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQueryTest.java
===================================================================
---
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQueryTest.java 2009-06-19
22:43:42 UTC (rev 1055)
+++
trunk/extensions/dna-connector-store-jpa/src/test/java/org/jboss/dna/connector/store/jpa/model/basic/SubgraphQueryTest.java 2009-06-20
15:13:29 UTC (rev 1056)
@@ -209,8 +209,9 @@
int snsIndex = path.getLastSegment().getIndex();
NamespaceEntity namespace = namespaces.get(childName.getNamespaceUri(), true);
UUID childUuid = UUID.randomUUID();
- ChildId id = new ChildId(workspaceId, parentUuid.toString(),
childUuid.toString());
- ChildEntity entity = new ChildEntity(id, ++numChildren, namespace,
childName.getLocalName(), snsIndex);
+ ChildId id = new ChildId(workspaceId, childUuid.toString());
+ ChildEntity entity = new ChildEntity(id, parentUuid.toString(), ++numChildren,
namespace, childName.getLocalName(),
+ snsIndex);
manager.persist(entity);
// Create the properties ...