DNA SVN: r1057 - trunk/dna-jcr/src/main/java/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-06-20 20:16:03 -0400 (Sat, 20 Jun 2009)
New Revision: 1057
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
Log:
DNA-469 SessionCache Does Not Handle Node Definitions Correctly After Move
Applied patch that fixed the issue above. It also properly clears the jcrNodes cache on a session refresh, sets the correct cardinality on the dnaint:nodeDefinition property from multi-valued to single-valued, and fixes a few cosmetic issues.
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-20 15:13:29 UTC (rev 1056)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-06-21 00:16:03 UTC (rev 1057)
@@ -277,12 +277,14 @@
// Removed any cached nodes not already in the changed or deleted set
this.cachedNodes.keySet().retainAll(retainedSet);
+ this.jcrNodes.keySet().retainAll(retainedSet);
} else {
// Throw out the old pending operations
this.requests.clear();
this.changedNodes.clear();
this.cachedNodes.clear();
this.deletedNodes.clear();
+ this.jcrNodes.clear();
}
}
@@ -364,6 +366,7 @@
this.cachedNodes.keySet().removeAll(nodesUnderBranch);
this.changedNodes.keySet().removeAll(nodesUnderBranch);
this.deletedNodes.keySet().removeAll(nodesUnderBranch);
+ this.jcrNodes.keySet().removeAll(nodesUnderBranch);
// Throw out the old pending operations
if (operations.isExecuteRequired()) {
@@ -1060,8 +1063,8 @@
workspaceName));
}
I18n msg = JcrI18n.unableToSetMultiValuedPropertyUsingSingleValue;
- throw new javax.jcr.ValueFormatException(msg.text(getPathFor(this.node).getString(namespaces),
- propertyName,
+ throw new javax.jcr.ValueFormatException(msg.text(propertyName.getString(namespaces),
+ getPathFor(this.node).getString(namespaces),
workspaceName));
}
@@ -1461,7 +1464,7 @@
ChildNode existingChild = node.getChildren().getChild(nodeUuid);
if (existingChild != null && nameDoesNotChange) return existingChild;
- JcrNodeDefinition definition = findBestNodeDefinition(node.getUuid(), newNodeName, null);
+ JcrNodeDefinition definition = findBestNodeDefinition(node.getUuid(), newNodeName, child.getPrimaryTypeName());
// Get an editor for the child (in its current location) and one for its parent ...
NodeEditor newChildEditor = getEditorFor(nodeUuid);
@@ -1469,9 +1472,9 @@
if (!definition.getId().equals(node.getDefinitionId())) {
// The node definition changed, so try to set the property ...
try {
- JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING, definition.getId()
- .getString());
- setProperty(DnaIntLexicon.NODE_DEFINITON, value);
+ JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING,
+ definition.getId().getString());
+ newChildEditor.setProperty(DnaIntLexicon.NODE_DEFINITON, value);
} catch (ConstraintViolationException e) {
// We can't set this property on the node (according to the node definition).
// But we still want the node info to have the correct node definition.
@@ -1693,15 +1696,17 @@
node.getMixinTypeNames(),
nodeDefinitionProp,
PropertyType.STRING,
- false,
+ true,
false);
+
if (nodeDefnDefn != null) {
PropertyDefinitionId nodeDefnDefinitionId = nodeDefnDefn.getId();
PropertyInfo nodeDefinitionInfo = new PropertyInfo(new PropertyId(desiredUuid, nodeDefinitionProp.getName()),
nodeDefnDefinitionId, PropertyType.STRING, nodeDefinitionProp,
- true, true, false);
+ false, true, false);
properties.put(nodeDefinitionProp.getName(), nodeDefinitionInfo);
}
+ assert nodeDefnDefn != null && nodeDefnDefn.getInternalName().equals(DnaIntLexicon.NODE_DEFINITON);
// Now create the child node info, putting it in the changed map (and not the cache map!) ...
NewNodeInfo newInfo = new NewNodeInfo(location, primaryTypeName, definition.getId(), node.getUuid(), properties);
@@ -1710,13 +1715,10 @@
// ---------------------------------------
// Now record the changes to the store ...
// ---------------------------------------
- Graph.Create<Graph.Batch> create = operations.createUnder(currentLocation)
- .nodeNamed(name)
- .with(desiredUuid)
- .with(primaryTypeProp);
- if (nodeDefnDefn != null) {
- create = create.with(nodeDefinitionProp);
- }
+ Graph.Create<Graph.Batch> create = operations.createUnder(currentLocation).nodeNamed(name).with(desiredUuid).with(primaryTypeProp);
+ // if (nodeDefnDefn != null) {
+ create = create.with(nodeDefinitionProp);
+ // }
create.and();
return result;
}
@@ -2091,18 +2093,19 @@
return info.getProperty(propertyId.getPropertyName());
}
- Path getPathFor(String workspaceName, UUID uuid, Path relativePath) throws NoSuchWorkspaceException, ItemNotFoundException, RepositoryException {
+ 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) {
+ } catch (InvalidWorkspaceException iwe) {
throw new NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(graph.getSourceName(), workspaceName));
}
-
+
try {
org.jboss.dna.graph.Node node;
if (uuid != null) {
@@ -2111,27 +2114,24 @@
if (relativePath != null) {
Path nodePath = node.getLocation().getPath();
Path absolutePath = relativePath.resolveAgainst(nodePath);
- node = graph.getNodeAt(absolutePath);
+ node = graph.getNodeAt(absolutePath);
}
-
- }
- else {
+
+ } else {
Path absolutePath = pathFactory.createAbsolutePath(relativePath.getSegmentsList());
- node = graph.getNodeAt(absolutePath);
+ node = graph.getNodeAt(absolutePath);
}
assert node != null;
-
+
return node.getLocation().getPath();
- }
- catch (org.jboss.dna.graph.property.PathNotFoundException pnfe) {
+ } catch (org.jboss.dna.graph.property.PathNotFoundException pnfe) {
throw new ItemNotFoundException(pnfe);
- }
- finally {
+ } finally {
graph.useWorkspace(this.workspaceName);
}
-
+
}
-
+
Path getPathFor( UUID uuid ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
if (uuid.equals(root)) return rootPath;
return getPathFor(findNodeInfo(uuid));
@@ -2537,8 +2537,8 @@
DnaIntLexicon.MULTI_VALUED_PROPERTIES,
values,
false);
- Property dnaProp = propertyFactory.create(DnaIntLexicon.MULTI_VALUED_PROPERTIES, newSingleMultiPropertyNames.iterator()
- .next());
+ Property dnaProp = propertyFactory.create(DnaIntLexicon.MULTI_VALUED_PROPERTIES,
+ newSingleMultiPropertyNames.iterator().next());
PropertyId propId = new PropertyId(uuid, dnaProp.getName());
JcrPropertyDefinition defn = (JcrPropertyDefinition)propertyDefinition;
return new PropertyInfo(propId, defn.getId(), PropertyType.STRING, dnaProp, defn.isMultiple(), true, false);
14 years, 10 months
DNA SVN: r1056 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector and 17 other directories.
by dna-commits@lists.jboss.org
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 ...
14 years, 10 months
DNA SVN: r1055 - in trunk/dna-jcr/src: test/java/org/jboss/dna/jcr and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-06-19 18:43:42 -0400 (Fri, 19 Jun 2009)
New Revision: 1055
Modified:
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/test/java/org/jboss/dna/jcr/SessionCacheTest.java
Log:
DNA-466 JCR requires connectors to expose UUID as identifier property
Changed the JCR implementation to use the path and UUID when both are known.
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:29 UTC (rev 1054)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-06-19 22:43:42 UTC (rev 1055)
@@ -280,13 +280,13 @@
*/
public void copy( String srcWorkspace,
String srcAbsPath,
- String destAbsPath )
- throws ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException,
- LockException, RepositoryException {
+ String destAbsPath )
+ 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));
}
@@ -313,8 +313,7 @@
try {
this.session.checkPermission(destPath.getParent(), "add_node");
- }
- catch (AccessControlException ace) {
+ } catch (AccessControlException ace) {
throw new AccessDeniedException(ace);
}
@@ -325,7 +324,7 @@
NodeInfo cacheParent = cache.findNodeInfo(null, destPath.getParent());
// Skip the cache and load the latest parent info directly from the graph
- NodeInfo parent = cache.loadFromGraph(cacheParent.getUuid(), null);
+ NodeInfo parent = cache.loadFromGraph(destPath.getParent(), cacheParent.getUuid());
Name newNodeName = destPath.getLastSegment().getName();
String parentPath = destPath.getParent().getString(this.context.getNamespaceRegistry());
@@ -334,18 +333,24 @@
Property primaryTypeProp = graph.getNodeAt(srcPath).getProperty(JcrLexicon.PRIMARY_TYPE);
Property uuidProp = graph.getNodeAt(srcPath).getProperty(DnaLexicon.UUID);
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()));
+ 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);
-
+
// Load the node that we just copied
- cache.compensateForWorkspaceChildChange(cacheParent.getUuid(), null, UUID.fromString(uuidProp.getFirstValue().toString()), newNodeName);
+ cache.compensateForWorkspaceChildChange(cacheParent.getUuid(),
+ null,
+ UUID.fromString(uuidProp.getFirstValue().toString()),
+ newNodeName);
}
/**
@@ -432,8 +437,7 @@
try {
this.session.checkPermission(srcAbsPath.substring(0, srcAbsPath.lastIndexOf('/')), "remove");
this.session.checkPermission(destAbsPath, "add_node");
- }
- catch (AccessControlException ace) {
+ } catch (AccessControlException ace) {
throw new AccessDeniedException(ace);
}
@@ -446,7 +450,7 @@
NodeInfo oldParent = cache.findNodeInfo(null, srcPath.getParent());
// Skip the cache and load the latest parent info directly from the graph
- NodeInfo parent = cache.loadFromGraph(cacheParent.getUuid(), null);
+ NodeInfo parent = cache.loadFromGraph(destPath.getParent(), cacheParent.getUuid());
Name newNodeName = destPath.getLastSegment().getName();
String parentPath = destPath.getParent().getString(this.context.getNamespaceRegistry());
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:29 UTC (rev 1054)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-06-19 22:43:42 UTC (rev 1055)
@@ -156,6 +156,7 @@
protected final HashMap<UUID, ImmutableNodeInfo> cachedNodes;
protected final HashMap<UUID, ChangedNodeInfo> changedNodes;
protected final HashMap<UUID, NodeInfo> deletedNodes;
+ protected final Map<UUID, Path> pathCache;
private LinkedList<Request> requests;
private BatchRequestBuilder requestBuilder;
@@ -191,6 +192,7 @@
this.cachedNodes = new HashMap<UUID, ImmutableNodeInfo>();
this.changedNodes = new HashMap<UUID, ChangedNodeInfo>();
this.deletedNodes = new HashMap<UUID, NodeInfo>();
+ this.pathCache = new HashMap<UUID, Path>();
// Create the batch operations ...
this.requests = new LinkedList<Request>();
@@ -1002,7 +1004,7 @@
// Or in the cache ...
NodeInfo cached = cachedNodes.get(uuid);
if (cached == null) {
- cached = loadFromGraph(uuid, null);
+ cached = loadFromGraph(null, uuid);
}
// Now put into the changed nodes ...
info = new ChangedNodeInfo(cached);
@@ -1400,6 +1402,9 @@
public void orderChildBefore( Path.Segment childToBeMoved,
Path.Segment before ) {
+ // Clear the path cache ...
+ SessionCache.this.pathCache.clear();
+
PathFactory pathFactory = SessionCache.this.pathFactory;
Path thisPath = this.currentLocation.getPath();
UUID fromUuid = this.node.getChildren().getChild(childToBeMoved).getUuid();
@@ -1477,6 +1482,9 @@
}
}
+ // Clear the path cache ...
+ SessionCache.this.pathCache.clear();
+
// Remove the node from the current parent and add it to this ...
ChangedNodeInfo newChildInfo = newChildEditor.node;
UUID existingParent = newChildInfo.getParent();
@@ -1874,7 +1882,7 @@
NodeInfo info = findNodeInfoInCache(uuid);
if (info == null) {
// Nope, so go ahead and load it ...
- info = loadFromGraph(uuid, null);
+ info = loadFromGraph(null, uuid);
}
SessionCache.this.checkPermission(info, JcrSession.JCR_READ_PERMISSION);
@@ -1919,7 +1927,7 @@
NodeInfo findNodeInfoForRoot() throws RepositoryException {
if (root == null) {
// We haven't found the root yet ...
- NodeInfo info = loadFromGraph(this.rootPath, null);
+ NodeInfo info = loadFromGraph(this.rootPath, (NodeInfo)null);
root = info.getUuid();
this.jcrNodes.put(root, new JcrRootNode(this, root));
return info;
@@ -2082,23 +2090,36 @@
}
Path getPathFor( UUID uuid ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
- if (uuid == root) return rootPath;
+ if (uuid.equals(root)) return rootPath;
return getPathFor(findNodeInfo(uuid));
}
Path getPathFor( NodeInfo info ) throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
- if (info != null && info.getUuid() == root) return rootPath;
- LinkedList<Path.Segment> segments = new LinkedList<Path.Segment>();
- while (info != null) {
+ if (info == null) {
+ return pathFactory.createRootPath();
+ }
+ UUID uuid = info.getUuid();
+ if (uuid.equals(root)) return rootPath;
+
+ // This isn't the root node ...
+ Path result = pathCache.get(uuid);
+ if (result == null) {
+ // We need to build a path using the parent path ...
UUID parent = info.getParent();
- if (parent == null) break;
- NodeInfo parentInfo = findNodeInfo(parent);
- ChildNode child = parentInfo.getChildren().getChild(info.getUuid());
- if (child == null) break;
- segments.addFirst(child.getSegment());
- info = parentInfo;
+ if (parent == null) {
+ // Then this node is the root ...
+ root = info.getUuid();
+ result = rootPath;
+ } else {
+ NodeInfo parentInfo = findNodeInfo(parent);
+ Path parentPath = getPathFor(parentInfo);
+ ChildNode child = parentInfo.getChildren().getChild(info.getUuid());
+ result = pathFactory.create(parentPath, child.getSegment());
+ }
+ pathCache.put(uuid, result);
}
- return pathFactory.createAbsolutePath(segments);
+ assert result != null;
+ return result;
}
Path getPathFor( PropertyInfo propertyInfo ) throws ItemNotFoundException, RepositoryException {
@@ -2138,18 +2159,20 @@
* Note that this method does not check the cache before loading from the repository graph.
* </p>
*
- * @param uuid the UUID of the node; may not be null
- * @param parentInfo the parent information; may be null if not known
+ * @param path the path of the node, if known; may be null only if the UUID is supplied
+ * @param uuid the UUID of the node, if known; may be null only if the path is supplied
* @return the information for the node
* @throws ItemNotFoundException if the node does not exist in the repository
* @throws RepositoryException if there was an error obtaining this information from the repository
*/
- protected ImmutableNodeInfo loadFromGraph( UUID uuid,
- NodeInfo parentInfo ) throws ItemNotFoundException, RepositoryException {
+ protected ImmutableNodeInfo loadFromGraph( Path path,
+ UUID uuid ) throws ItemNotFoundException, RepositoryException {
// Load the node information from the store ...
try {
- org.jboss.dna.graph.Node node = store.getNodeAt(uuid);
- ImmutableNodeInfo info = createNodeInfoFrom(node, parentInfo);
+ // See if there is a path for this uuid ...
+ Location location = Location.create(path, uuid);
+ org.jboss.dna.graph.Node node = store.getNodeAt(location);
+ ImmutableNodeInfo info = createNodeInfoFrom(node, null);
this.cachedNodes.put(info.getUuid(), info);
return info;
} catch (org.jboss.dna.graph.property.PathNotFoundException e) {
@@ -2540,6 +2563,9 @@
// Whether or not we found an info, add it to the deleted map ...
this.deletedNodes.put(toDelete, info);
+ // Remove it from the path cache ...
+ this.pathCache.remove(toDelete);
+
if (info != null) {
// Get all the children and add them to the queue ...
for (ChildNode child : info.getChildren()) {
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java 2009-06-19 22:43:29 UTC (rev 1054)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java 2009-06-19 22:43:42 UTC (rev 1055)
@@ -373,7 +373,7 @@
sw.stop();
assertThat(nodeInfo, is(sameInstance(cache.findNodeInfo(rootUuid))));
}
- System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
+ // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
}
@Test
@@ -391,7 +391,7 @@
sw.stop();
assertThat(rootInfo, is(notNullValue()));
}
- System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
+ // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
}
@Test
@@ -409,7 +409,7 @@
sw.stop();
assertThat(rootInfo, is(notNullValue()));
}
- System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
+ // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
}
@Test
@@ -437,7 +437,7 @@
sw.stop();
assertThat(lr3.getUuid(), is(lr3Node.getLocation().getUuid()));
assertSameProperties(lr3, lr3Node);
- System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
+ // System.out.println(pad(sourceName) + " ==> " + sw.getSimpleStatistics());
// Verify that this loaded all the intermediate nodes, by walking up ...
NodeInfo info = lr3;
@@ -761,16 +761,18 @@
@Test
public void shouldFindInfoForAllNodesInGraph() throws Exception {
- Stopwatch sw = new Stopwatch();
+ for (int i = 0; i != 3; ++i) {
+ Stopwatch sw = new Stopwatch();
- // Get the root ...
- sw.start();
- NodeInfo root = cache.findNodeInfoForRoot();
- cache.getPathFor(root);
- sw.stop();
+ // Get the root ...
+ sw.start();
+ NodeInfo root = cache.findNodeInfoForRoot();
+ cache.getPathFor(root);
+ sw.stop();
- // Walk the infos for nodes under the root (this is recursive) ...
- walkInfosForNodesUnder(root, sw);
- System.out.println("Statistics for walking nodes using SessionCache: " + sw.getSimpleStatistics());
+ // Walk the infos for nodes under the root (this is recursive) ...
+ walkInfosForNodesUnder(root, sw);
+ System.out.println("Statistics for walking nodes using SessionCache: " + sw.getSimpleStatistics());
+ }
}
}
14 years, 10 months
DNA SVN: r1054 - in trunk: dna-jcr/.settings and 5 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-06-19 18:43:29 -0400 (Fri, 19 Jun 2009)
New Revision: 1054
Removed:
trunk/dna-jcr/.settings/org.eclipse.jdt.core.prefs
trunk/dna-jcr/.settings/org.eclipse.wst.common.component
trunk/dna-jcr/.settings/org.eclipse.wst.common.project.facet.core.xml
Modified:
trunk/dna-integration-tests/pom.xml
trunk/dna-jcr-tck/pom.xml
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java
trunk/docs/examples/gettingstarted/repositories/pom.xml
trunk/docs/examples/gettingstarted/sequencers/pom.xml
trunk/extensions/dna-classloader-maven/pom.xml
Log:
Correct several POM files to more accurately reflect direct dependencies and usage
Modified: trunk/dna-integration-tests/pom.xml
===================================================================
--- trunk/dna-integration-tests/pom.xml 2009-06-17 17:19:39 UTC (rev 1053)
+++ trunk/dna-integration-tests/pom.xml 2009-06-19 22:43:29 UTC (rev 1054)
@@ -7,8 +7,8 @@
</parent>
<!-- The groupId and version values are inherited from parent -->
<artifactId>dna-integration-tests</artifactId>
+ <description>The JBoss DNA integration tests</description>
<packaging>jar</packaging>
- <version>0.6-SNAPSHOT</version>
<name>JBoss DNA Integration Tests</name>
<url>http://labs.jboss.org/dna</url>
Deleted: trunk/dna-jcr/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- trunk/dna-jcr/.settings/org.eclipse.jdt.core.prefs 2009-06-17 17:19:39 UTC (rev 1053)
+++ trunk/dna-jcr/.settings/org.eclipse.jdt.core.prefs 2009-06-19 22:43:29 UTC (rev 1054)
@@ -1,7 +0,0 @@
-#Fri May 15 17:59:45 EDT 2009
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
-org.eclipse.jdt.core.compiler.compliance=1.6
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.6
Deleted: trunk/dna-jcr/.settings/org.eclipse.wst.common.component
===================================================================
--- trunk/dna-jcr/.settings/org.eclipse.wst.common.component 2009-06-17 17:19:39 UTC (rev 1053)
+++ trunk/dna-jcr/.settings/org.eclipse.wst.common.component 2009-06-19 22:43:29 UTC (rev 1054)
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project-modules id="moduleCoreId" project-version="1.5.0">
- <wb-module deploy-name="dna-jcr">
- <wb-resource deploy-path="/" source-path="/src/main/java"/>
- <wb-resource deploy-path="/" source-path="/src/main/resources"/>
- <wb-resource deploy-path="/" source-path="/src/test/java"/>
- <wb-resource deploy-path="/" source-path="/src/test/resources"/>
- </wb-module>
-</project-modules>
Deleted: trunk/dna-jcr/.settings/org.eclipse.wst.common.project.facet.core.xml
===================================================================
--- trunk/dna-jcr/.settings/org.eclipse.wst.common.project.facet.core.xml 2009-06-17 17:19:39 UTC (rev 1053)
+++ trunk/dna-jcr/.settings/org.eclipse.wst.common.project.facet.core.xml 2009-06-19 22:43:29 UTC (rev 1054)
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<faceted-project>
- <installed facet="jst.java" version="6.0"/>
- <installed facet="jst.utility" version="1.0"/>
-</faceted-project>
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java 2009-06-17 17:19:39 UTC (rev 1053)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/SessionCacheTest.java 2009-06-19 22:43:29 UTC (rev 1054)
@@ -60,6 +60,7 @@
import org.jboss.dna.graph.property.ValueFactory;
import org.jboss.dna.jcr.SessionCache.NodeEditor;
import org.jboss.dna.jcr.Vehicles.Lexicon;
+import org.jboss.dna.jcr.cache.ChildNode;
import org.jboss.dna.jcr.cache.Children;
import org.jboss.dna.jcr.cache.NodeInfo;
import org.jboss.dna.jcr.cache.PropertyInfo;
@@ -744,4 +745,32 @@
db9 = cache.findNodeInfo(root.getUuid(), path("/vehix:Vehicles/vehix:Cars/vehix:Sports/vehix:Aston Martin DB9"));
assertNoProperty(db9, Lexicon.LENGTH_IN_INCHES);
}
+
+ protected void walkInfosForNodesUnder( NodeInfo parentInfo,
+ Stopwatch sw ) throws Exception {
+ for (ChildNode child : parentInfo.getChildren()) {
+ sw.start();
+ NodeInfo childInfo = cache.findNodeInfo(child.getUuid());
+ cache.getPathFor(childInfo);
+ sw.stop();
+
+ // Walk the infos for nodes under the child (this is recursive) ...
+ walkInfosForNodesUnder(childInfo, sw);
+ }
+ }
+
+ @Test
+ public void shouldFindInfoForAllNodesInGraph() throws Exception {
+ Stopwatch sw = new Stopwatch();
+
+ // Get the root ...
+ sw.start();
+ NodeInfo root = cache.findNodeInfoForRoot();
+ cache.getPathFor(root);
+ sw.stop();
+
+ // Walk the infos for nodes under the root (this is recursive) ...
+ walkInfosForNodesUnder(root, sw);
+ System.out.println("Statistics for walking nodes using SessionCache: " + sw.getSimpleStatistics());
+ }
}
Modified: trunk/dna-jcr-tck/pom.xml
===================================================================
--- trunk/dna-jcr-tck/pom.xml 2009-06-17 17:19:39 UTC (rev 1053)
+++ trunk/dna-jcr-tck/pom.xml 2009-06-19 22:43:29 UTC (rev 1054)
@@ -4,7 +4,7 @@
<parent>
<groupId>org.jboss.dna</groupId>
<artifactId>dna</artifactId>
- <version>0.5-SNAPSHOT</version>
+ <version>0.6-SNAPSHOT</version>
</parent>
<!-- The groupId and version values are inherited from parent -->
<artifactId>dna-jcr-tck</artifactId>
Modified: trunk/docs/examples/gettingstarted/repositories/pom.xml
===================================================================
--- trunk/docs/examples/gettingstarted/repositories/pom.xml 2009-06-17 17:19:39 UTC (rev 1053)
+++ trunk/docs/examples/gettingstarted/repositories/pom.xml 2009-06-19 22:43:29 UTC (rev 1054)
@@ -18,15 +18,15 @@
<dependencies>
<dependency>
<groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
<artifactId>dna-repository</artifactId>
- <version>${pom.version}</version>
- <scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
<artifactId>dna-jcr</artifactId>
- <version>${pom.version}</version>
- <scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
Modified: trunk/docs/examples/gettingstarted/sequencers/pom.xml
===================================================================
--- trunk/docs/examples/gettingstarted/sequencers/pom.xml 2009-06-17 17:19:39 UTC (rev 1053)
+++ trunk/docs/examples/gettingstarted/sequencers/pom.xml 2009-06-19 22:43:29 UTC (rev 1054)
@@ -18,9 +18,15 @@
<dependencies>
<dependency>
<groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.dna</groupId>
<artifactId>dna-jcr</artifactId>
- <version>${pom.version}</version>
- <scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jboss.dna</groupId>
Modified: trunk/extensions/dna-classloader-maven/pom.xml
===================================================================
--- trunk/extensions/dna-classloader-maven/pom.xml 2009-06-17 17:19:39 UTC (rev 1053)
+++ trunk/extensions/dna-classloader-maven/pom.xml 2009-06-19 22:43:29 UTC (rev 1054)
@@ -4,6 +4,7 @@
<groupId>org.jboss.dna</groupId>
<artifactId>dna</artifactId>
<version>0.6-SNAPSHOT</version>
+ <relativePath>../..</relativePath>
</parent>
<!-- The groupId and version values are inherited from parent -->
<artifactId>dna-classloader-maven</artifactId>
14 years, 10 months
DNA SVN: r1053 - trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-06-17 13:19:39 -0400 (Wed, 17 Jun 2009)
New Revision: 1053
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/FederatedRequest.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ProjectedNode.java
Log:
DNA-463 Federation connector incorrectly expects identification properties on all source nodes
Corrected the for loop that is aggregating the identifier properties on source node locations. If the location does not even have identifier properties, then this aggregation process is not even performed.
Also added toString() implementations for ProjectedNode and FederatedRequest.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/FederatedRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/FederatedRequest.java 2009-06-17 17:19:33 UTC (rev 1052)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/FederatedRequest.java 2009-06-17 17:19:39 UTC (rev 1053)
@@ -93,6 +93,24 @@
if (forkLatch != null) forkLatch.await();
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Federated request: ").append(original).append("\n");
+ sb.append(" projected to: ").append("\n");
+ ProjectedRequest projected = first;
+ while (projected != null) {
+ sb.append(" - ").append(projected).append("\n");
+ projected = projected.next();
+ }
+ return sb.toString();
+ }
+
class ProjectedRequest {
private final Projection projection;
private final Projection projection2;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinRequestProcessor.java 2009-06-17 17:19:33 UTC (rev 1052)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinRequestProcessor.java 2009-06-17 17:19:39 UTC (rev 1053)
@@ -203,19 +203,20 @@
}
// Make sure we have an actual location ...
- actualLocation = determineActualLocation(actualLocation,
- readFromSource.getActualLocationOfNode(),
- projectedRequest.getProjection());
+ Location sourceLocation = readFromSource.getActualLocationOfNode();
+ actualLocation = determineActualLocation(actualLocation, sourceLocation, projectedRequest.getProjection());
- // Accumulate the identification properties ...
- for (Property propertyInSource : readFromSource.getActualLocationOfNode().getIdProperties()) {
- Name name = propertyInSource.getName();
- Property existing = actualLocation.getIdProperty(name);
- if (existing != null) {
- // Merge the property values ...
- propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ if (sourceLocation.hasIdProperties()) {
+ // Accumulate the identification properties ...
+ for (Property propertyInSource : sourceLocation.getIdProperties()) {
+ Name name = propertyInSource.getName();
+ Property existing = actualLocation.getIdProperty(name);
+ if (existing != null) {
+ // Merge the property values ...
+ propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ }
+ actualLocation = actualLocation.with(propertyInSource);
}
- actualLocation = actualLocation.with(propertyInSource);
}
setCacheableInfo(request, readFromSource.getCachePolicy());
projectedRequest = projectedRequest.next();
@@ -268,19 +269,22 @@
if (federatedPath == null) federatedPath = childInRepos.getPath().getParent();
} else {
ReadNodeRequest readFromSource = (ReadNodeRequest)sourceRequest;
- // Accumulate the identification properties ...
- for (Property propertyInSource : readFromSource.getActualLocationOfNode().getIdProperties()) {
- Name name = propertyInSource.getName();
- Property existing = actualLocation.getIdProperty(name);
- if (existing != null) {
- // Merge the property values ...
- propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ Location sourceLocation = readFromSource.getActualLocationOfNode();
+ if (sourceLocation.hasIdProperties()) {
+ // Accumulate the identification properties ...
+ for (Property propertyInSource : sourceLocation.getIdProperties()) {
+ Name name = propertyInSource.getName();
+ Property existing = actualLocation.getIdProperty(name);
+ if (existing != null) {
+ // Merge the property values ...
+ propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ }
+ actualLocation = actualLocation.with(propertyInSource);
}
- actualLocation = actualLocation.with(propertyInSource);
}
// Make sure we have an actual location ...
- actualLocation = determineActualLocation(actualLocation, readFromSource.getActualLocationOfNode(), projection);
+ actualLocation = determineActualLocation(actualLocation, sourceLocation, projection);
if (federatedPath == null) federatedPath = actualLocation.getPath();
// Add all the children from the source ...
@@ -416,15 +420,18 @@
if (federatedPath == null) federatedPath = childInRepos.getPath().getParent();
} else {
ReadAllChildrenRequest readFromSource = (ReadAllChildrenRequest)sourceRequest;
- // Accumulate the identification properties ...
- for (Property propertyInSource : readFromSource.getActualLocationOfNode().getIdProperties()) {
- Name name = propertyInSource.getName();
- Property existing = actualLocation.getIdProperty(name);
- if (existing != null) {
- // Merge the property values ...
- propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ Location sourceLocation = readFromSource.getActualLocationOfNode();
+ if (sourceLocation.hasIdProperties()) {
+ // Accumulate the identification properties ...
+ for (Property propertyInSource : sourceLocation.getIdProperties()) {
+ Name name = propertyInSource.getName();
+ Property existing = actualLocation.getIdProperty(name);
+ if (existing != null) {
+ // Merge the property values ...
+ propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ }
+ actualLocation = actualLocation.with(propertyInSource);
}
- actualLocation = actualLocation.with(propertyInSource);
}
// Make sure we have an actual location ...
@@ -498,19 +505,20 @@
}
// Make sure we have an actual location ...
- actualLocation = determineActualLocation(actualLocation,
- readFromSource.getActualLocationOfNode(),
- projectedRequest.getProjection());
+ Location sourceLocation = readFromSource.getActualLocationOfNode();
+ actualLocation = determineActualLocation(actualLocation, sourceLocation, projectedRequest.getProjection());
- // Accumulate the identification properties ...
- for (Property propertyInSource : readFromSource.getActualLocationOfNode().getIdProperties()) {
- Name name = propertyInSource.getName();
- Property existing = actualLocation.getIdProperty(name);
- if (existing != null) {
- // Merge the property values ...
- propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ if (sourceLocation.hasIdProperties()) {
+ // Accumulate the identification properties ...
+ for (Property propertyInSource : sourceLocation.getIdProperties()) {
+ Name name = propertyInSource.getName();
+ Property existing = actualLocation.getIdProperty(name);
+ if (existing != null) {
+ // Merge the property values ...
+ propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ }
+ actualLocation = actualLocation.with(propertyInSource);
}
- actualLocation = actualLocation.with(propertyInSource);
}
// Add all the properties ...
@@ -559,19 +567,20 @@
}
// Make sure we have an actual location ...
- actualLocation = determineActualLocation(actualLocation,
- readFromSource.getActualLocationOfNode(),
- projectedRequest.getProjection());
+ Location sourceLocation = readFromSource.getActualLocationOfNode();
+ actualLocation = determineActualLocation(actualLocation, sourceLocation, projectedRequest.getProjection());
- // Accumulate the identification properties ...
- for (Property propertyInSource : readFromSource.getActualLocationOfNode().getIdProperties()) {
- Name name = propertyInSource.getName();
- Property existing = actualLocation.getIdProperty(name);
- if (existing != null) {
- // Merge the property values ...
- propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ if (sourceLocation.hasIdProperties()) {
+ // Accumulate the identification properties ...
+ for (Property propertyInSource : sourceLocation.getIdProperties()) {
+ Name name = propertyInSource.getName();
+ Property existing = actualLocation.getIdProperty(name);
+ if (existing != null) {
+ // Merge the property values ...
+ propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ }
+ actualLocation = actualLocation.with(propertyInSource);
}
- actualLocation = actualLocation.with(propertyInSource);
}
// Add all the properties ...
@@ -930,15 +939,18 @@
return;
}
- // Accumulate the identification properties ...
- for (Property propertyInSource : readFromSource.getActualLocationOfNode().getIdProperties()) {
- Name name = propertyInSource.getName();
- Property existing = actualLocation.getIdProperty(name);
- if (existing != null) {
- // Merge the property values ...
- propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ Location sourceLocation = readFromSource.getActualLocationOfNode();
+ if (sourceLocation.hasIdProperties()) {
+ // Accumulate the identification properties ...
+ for (Property propertyInSource : sourceLocation.getIdProperties()) {
+ Name name = propertyInSource.getName();
+ Property existing = actualLocation.getIdProperty(name);
+ if (existing != null) {
+ // Merge the property values ...
+ propertyInSource = merge(existing, propertyInSource, propertyFactory, true);
+ }
+ actualLocation = actualLocation.with(propertyInSource);
}
- actualLocation = actualLocation.with(propertyInSource);
}
projectedRequest = projectedRequest.next();
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ProjectedNode.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ProjectedNode.java 2009-06-17 17:19:33 UTC (rev 1052)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ProjectedNode.java 2009-06-17 17:19:39 UTC (rev 1053)
@@ -121,6 +121,11 @@
public ProxyNode asProxy() {
return null;
}
+
+ @Override
+ public String toString() {
+ return "Placeholder " + location();
+ }
}
@NotThreadSafe
@@ -196,4 +201,10 @@
public boolean isSameLocationAsOriginal() {
return this.sameLocationAsOriginal;
}
+
+ @Override
+ public String toString() {
+ return "Proxy for " + federatedLocation() + " projected from " + location() + " in workspace \"" + workspaceName()
+ + "\" in \"" + source() + "\"";
+ }
}
14 years, 10 months
DNA SVN: r1052 - in trunk/dna-jcr/src: test/java/org/jboss/dna/jcr and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-06-17 13:19:33 -0400 (Wed, 17 Jun 2009)
New Revision: 1052
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java
Log:
DNA-399 Need to Add Session.checkPermission Calls to Guard Read, Add Node, Set Property, and Remove Item Access
DNA-453 Implement Workspace.copy(String, String, String)
Corrected JavaDoc and changed private method to protected to eliminate performance warning.
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-15 14:54:13 UTC (rev 1051)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/SessionCache.java 2009-06-17 17:19:33 UTC (rev 1052)
@@ -233,13 +233,13 @@
/**
* Checks whether the current session has the appropriate permissions to perform the given action.
*
- * @param the node on which the action will be performed
+ * @param node the node on which the action will be performed
* @param action the name of the action to perform, should be "add_node", "remove", or "set_property"
* @throws AccessDeniedException if the current session does not have the requisite privileges to perform this task
* @throws RepositoryException if any other error occurs
*/
- private void checkPermission( NodeInfo node,
- String action ) throws AccessDeniedException, RepositoryException {
+ protected void checkPermission( NodeInfo node,
+ String action ) throws AccessDeniedException, RepositoryException {
try {
this.session.checkPermission(SessionCache.this.getPathFor(node), action);
} catch (AccessControlException ace) {
@@ -1462,8 +1462,8 @@
if (!definition.getId().equals(node.getDefinitionId())) {
// The node definition changed, so try to set the property ...
try {
- JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING,
- definition.getId().getString());
+ JcrValue value = new JcrValue(factories(), SessionCache.this, PropertyType.STRING, definition.getId()
+ .getString());
setProperty(DnaIntLexicon.NODE_DEFINITON, value);
} catch (ConstraintViolationException e) {
// We can't set this property on the node (according to the node definition).
@@ -1859,6 +1859,7 @@
*
* @param uuid the UUID for the node; may not be null
* @return the information for the node with the supplied UUID, or null if the information is not in the cache
+ * @throws AccessDeniedException if the node cannot be accessed
* @throws ItemNotFoundException if there is no node with the supplied UUID
* @throws InvalidItemStateException if the node with the UUID has been deleted in this session
* @throws RepositoryException if any other error occurs while reading information from the repository
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java 2009-06-15 14:54:13 UTC (rev 1051)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java 2009-06-17 17:19:33 UTC (rev 1052)
@@ -12,19 +12,19 @@
/**
* Additional DNA tests that check for JCR compliance.
- *
*/
public class DnaTckTest extends AbstractJCRTest {
Session session;
+ @Override
protected void tearDown() throws Exception {
try {
superuser.getRootNode().getNode(this.nodeName1).remove();
superuser.save();
+ } catch (PathNotFoundException ignore) {
}
- catch (PathNotFoundException ignore) { }
-
+
if (session != null) {
session.logout();
session = null;
@@ -32,22 +32,22 @@
super.tearDown();
}
- private void testRead(Session session) throws Exception {
+ private void testRead( Session session ) throws Exception {
Node rootNode = session.getRootNode();
-
- for (NodeIterator iter = rootNode.getNodes(); iter.hasNext(); ) {
+
+ for (NodeIterator iter = rootNode.getNodes(); iter.hasNext();) {
iter.nextNode();
}
}
-
- private void testAddNode(Session session) throws Exception {
+
+ private void testAddNode( Session session ) throws Exception {
session.refresh(false);
Node root = session.getRootNode();
root.addNode(nodeName1, testNodeType);
session.save();
}
-
- private void testRemoveNode(Session session) throws Exception {
+
+ private void testRemoveNode( Session session ) throws Exception {
session.refresh(false);
Node root = session.getRootNode();
Node node = root.getNode(nodeName1);
@@ -55,31 +55,30 @@
session.save();
}
- private void testSetProperty(Session session) throws Exception {
+ private void testSetProperty( Session session ) throws Exception {
session.refresh(false);
Node root = session.getRootNode();
root.setProperty(this.propertyName1, "test value");
session.save();
-
+
}
-
- private void testRemoveProperty(Session session) throws Exception {
+
+ private void testRemoveProperty( Session session ) throws Exception {
Session localAdmin = helper.getRepository().login(helper.getSuperuserCredentials(), session.getWorkspace().getName());
assertEquals(session.getWorkspace().getName(), superuser.getWorkspace().getName());
-
+
Node superRoot = localAdmin.getRootNode();
Node superNode;
try {
superNode = superRoot.getNode(this.nodeName1);
- }
- catch (PathNotFoundException pnfe) {
+ } catch (PathNotFoundException pnfe) {
superNode = superRoot.addNode(nodeName1, testNodeType);
}
superNode.setProperty(this.propertyName1, "test value");
localAdmin.save();
localAdmin.logout();
-
+
session.refresh(false);
Node root = session.getRootNode();
Node node = root.getNode(nodeName1);
@@ -87,8 +86,8 @@
property.remove();
session.save();
}
-
- private void testWrite(Session session) throws Exception {
+
+ private void testWrite( Session session ) throws Exception {
testAddNode(session);
testSetProperty(session);
testRemoveProperty(session);
@@ -97,6 +96,7 @@
/**
* Tests that read-only sessions can read nodes by loading all of the children of the root node
+ *
* @throws Exception
*/
public void testShouldAllowReadOnlySessionToRead() throws Exception {
@@ -106,6 +106,7 @@
/**
* Tests that read-only sessions cannot add nodes, remove nodes, set nodes, or set properties.
+ *
* @throws Exception
*/
public void testShouldNotAllowReadOnlySessionToWrite() throws Exception {
@@ -113,31 +114,28 @@
try {
testAddNode(session);
fail("Read-only sessions should not be able to add nodes");
+ } catch (AccessDeniedException expected) {
}
- catch (AccessDeniedException expected) {
- }
try {
testSetProperty(session);
fail("Read-only sessions should not be able to set properties");
+ } catch (AccessDeniedException expected) {
}
- catch (AccessDeniedException expected) {
- }
try {
testRemoveProperty(session);
fail("Read-only sessions should not be able to remove properties");
+ } catch (AccessDeniedException expected) {
}
- catch (AccessDeniedException expected) {
- }
try {
testRemoveNode(session);
fail("Read-only sessions should not be able to remove nodes");
+ } catch (AccessDeniedException expected) {
}
- catch (AccessDeniedException expected) {
- }
}
-
+
/**
* Tests that read-write sessions can read nodes by loading all of the children of the root node
+ *
* @throws Exception
*/
public void testShouldAllowReadWriteSessionToRead() throws Exception {
@@ -147,6 +145,7 @@
/**
* Tests that read-write sessions can add nodes, remove nodes, set nodes, and set properties.
+ *
* @throws Exception
*/
public void testShouldAllowReadWriteSessionToWrite() throws Exception {
@@ -155,8 +154,9 @@
}
/**
- * User defaultuser is configured to have readwrite in "otherWorkspace" and readonly in the default
- * workspace. This test makes sure both work.
+ * User defaultuser is configured to have readwrite in "otherWorkspace" and readonly in the default workspace. This test makes
+ * sure both work.
+ *
* @throws Exception
*/
public void testShouldMapRolesToWorkspacesWhenSpecified() throws Exception {
@@ -165,21 +165,19 @@
testRead(session);
testWrite(session);
-
+
session.logout();
-
+
session = helper.getRepository().login(creds, "otherWorkspace");
testRead(session);
try {
testWrite(session);
fail("User 'defaultuser' should not have write access to 'otherWorkspace'");
+ } catch (AccessDeniedException expected) {
}
- catch (AccessDeniedException expected) {
- }
session.logout();
}
-
public void testShouldCopyFromAnotherWorkspace() throws Exception {
session = helper.getSuperuserSession("otherWorkspace");
String nodetype1 = this.getProperty("nodetype");
@@ -187,16 +185,16 @@
node1.addNode(nodeName2, nodetype1);
session.save();
session.logout();
-
+
superuser.getRootNode().addNode(nodeName4, nodetype1);
superuser.save();
-
+
superuser.getWorkspace().copy("otherWorkspace", "/" + nodeName1, "/" + nodeName4 + "/" + nodeName1);
-
+
Node node4 = superuser.getRootNode().getNode(nodeName4);
Node node4node1 = node4.getNode(nodeName1);
Node node4node1node2 = node4node1.getNode(nodeName2);
-
+
assertNotNull(node4node1node2);
}
}
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-15 14:54:13 UTC (rev 1051)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrRepositoryTest.java 2009-06-17 17:19:33 UTC (rev 1052)
@@ -184,7 +184,6 @@
repository.login();
}
- @SuppressWarnings("cast")
@Test
public void shouldAllowLoginWithNoCredentialsInPrivilegedBlock() throws Exception {
LoginContext login = new LoginContext("dna-jcr", new UserPasswordCallbackHandler("superuser", "superuser".toCharArray()));
14 years, 10 months
DNA SVN: r1051 - trunk/dna-graph/src/main/java/org/jboss/dna/graph/request.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-06-15 10:54:13 -0400 (Mon, 15 Jun 2009)
New Revision: 1051
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UuidConflictBehavior.java
Log:
Added missing file to fix breaks in nightly build
Added: 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 (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UuidConflictBehavior.java 2009-06-15 14:54:13 UTC (rev 1051)
@@ -0,0 +1,15 @@
+package org.jboss.dna.graph.request;
+
+/**
+ * An enumeration used by {@link CopyBranchRequest} for the choice of handling duplicate UUIDs, such as when a node is to be
+ * copied to another location where a node already exists.
+ *
+ * @author Randall Hauch
+ */
+public enum UuidConflictBehavior {
+
+ ALWAYS_CREATE_NEW_UUID,
+ DO_NOT_COPY,
+ REPLACE_EXISTING_NODE,
+ THROW_EXCEPTION;
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UuidConflictBehavior.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
14 years, 10 months
DNA SVN: r1050 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector/federation and 5 other directories.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-06-14 18:58:57 -0400 (Sun, 14 Jun 2009)
New Revision: 1050
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ForkRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java
trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
Log:
DNA-453 Implement Workspace.copy(String, String, String)
Applied patch that modifies the copy operation in Graph and Graph.Batch to support the "fromWorkspace" construct, allowing users to specify that the source node is in a workspace other than the current workspace. The patch also moves the JcrWorkspace.copy(String, String) code into JcrWorkspace.copy(String, String, String) and generalizes it to support source nodes in workspaces other than the workspace represented by the JcrWorkspace.
The patch modifies JcrWorkspace.copy(String, String) to call JcrWorkspace.copy(String, String, String) with the name of the current workspace as the source workspace. This allows for the corner cases of the JcrWorkspace.copy(String, String, String) to be tested by the JR TCK tests. Added an additional test to DnaTckTest to test copying from workspace to another. For some reason the JR TCK tests don't actually do this.
Finally, the patch adds the concept of UuidConflictBehavior to the copy operation and CopyBranchRequest. This feature is not yet implemented in the request processors, but is needed in order to implement the JcrWorkspace.clone(...) and update(String) methods as copies from one workspace to another.
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-13 15:56:00 UTC (rev 1049)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-06-14 22:58:57 UTC (rev 1050)
@@ -78,6 +78,7 @@
import org.jboss.dna.graph.request.Request;
import org.jboss.dna.graph.request.RequestBuilder;
import org.jboss.dna.graph.request.UnsupportedRequestException;
+import org.jboss.dna.graph.request.UuidConflictBehavior;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest.CloneConflictBehavior;
import org.jboss.dna.graph.request.CreateWorkspaceRequest.CreateConflictBehavior;
@@ -564,17 +565,19 @@
public Copy<Graph> copy( Location from ) {
return new CopyAction<Graph>(this, from) {
@Override
- protected Graph submit( Locations from,
+ protected Graph submit( String fromWorkspaceName,
+ Locations from,
Location into,
Name childName ) {
- String workspaceName = getCurrentWorkspaceName();
+ String workspaceName = fromWorkspaceName != null ? fromWorkspaceName : getCurrentWorkspaceName();
do {
requests.copyBranch(from.getLocation(),
workspaceName,
into,
- workspaceName,
+ getCurrentWorkspaceName(),
childName,
- NodeConflictBehavior.APPEND);
+ NodeConflictBehavior.APPEND,
+ UuidConflictBehavior.ALWAYS_CREATE_NEW_UUID);
} while ((from = from.next()) != null);
return and();
}
@@ -1734,15 +1737,13 @@
}
public List<Location> under( Location at ) {
- return requests.readBlockOfChildren(at, getCurrentWorkspaceName(), startingIndex, blockSize)
- .getChildren();
+ return requests.readBlockOfChildren(at, getCurrentWorkspaceName(), startingIndex, blockSize).getChildren();
}
};
}
public List<Location> startingAfter( final Location previousSibling ) {
- return requests.readNextBlockOfChildren(previousSibling, getCurrentWorkspaceName(), blockSize)
- .getChildren();
+ return requests.readNextBlockOfChildren(previousSibling, getCurrentWorkspaceName(), blockSize).getChildren();
}
public List<Location> startingAfter( String pathOfPreviousSibling ) {
@@ -2368,12 +2369,19 @@
assertNotExecuted();
return new CopyAction<BatchConjunction>(this.nextRequests, from) {
@Override
- protected BatchConjunction submit( Locations from,
+ protected BatchConjunction submit( String fromWorkspaceName,
+ Locations from,
Location into,
Name copyName ) {
- String workspaceName = getCurrentWorkspaceName();
+ String workspaceName = fromWorkspaceName != null ? fromWorkspaceName : getCurrentWorkspaceName();
do {
- requestQueue.copyBranch(from.getLocation(), workspaceName, into, workspaceName, copyName);
+ requestQueue.copyBranch(from.getLocation(),
+ workspaceName,
+ into,
+ workspaceName,
+ copyName,
+ null,
+ UuidConflictBehavior.ALWAYS_CREATE_NEW_UUID);
} while ((from = from.next()) != null);
return and();
}
@@ -3993,10 +4001,36 @@
* @param <Next> The interface that is to be returned when this request is completed
* @author Randall Hauch
*/
- public interface Copy<Next> extends To<Next>, Into<Next>, And<Copy<Next>> {
+ public interface Copy<Next>
+ extends WithUuids<FromWorkspace<CopyTarget<Next>>>, FromWorkspace<CopyTarget<Next>>, CopyTarget<Next>, And<Copy<Next>> {
}
+ public interface CopyTarget<Next> extends To<Next>, Into<Next> {
+ }
+
/**
+ * The interface for specifying that a node should come from a workspace other than the current workspace.
+ *
+ * @param <Next> The interface that is to be returned when this request is completed
+ */
+ public interface FromWorkspace<Next> {
+ Next fromWorkspace( String workspaceName );
+ }
+
+ /**
+ * The interface for specifying how UUID conflicts should be handled.
+ *
+ * @param <Next> The interface that is to be returned when this request is completed
+ */
+ public interface WithUuids<Next> {
+ Next removingMatchingUuids();
+
+ Next failingIfUuidsMatch();
+
+ Next unlessMatchingUuidExists();
+ }
+
+ /**
* The interface for defining additional properties on a new node.
*
* @param <Next> The interface that is to be returned when this create request is completed
@@ -5473,10 +5507,7 @@
}
public SubgraphNode getNode( Name relativePath ) {
- Path path = getGraph().getContext()
- .getValueFactories()
- .getPathFactory()
- .create(getLocation().getPath(), relativePath);
+ Path path = getGraph().getContext().getValueFactories().getPathFactory().create(getLocation().getPath(), relativePath);
path = path.getNormalizedPath();
return getNode(path);
}
@@ -5762,12 +5793,16 @@
@NotThreadSafe
protected abstract class CopyAction<T> extends AbstractAction<T> implements Copy<T> {
- private final Locations from;
+ protected Locations from;
+ protected String fromWorkspaceName;
+ protected UuidConflictBehavior uuidConflictBehavior;
/*package*/CopyAction( T afterConjunction,
Location from ) {
super(afterConjunction);
this.from = new Locations(from);
+ this.fromWorkspaceName = Graph.this.getCurrentWorkspaceName();
+ this.uuidConflictBehavior = UuidConflictBehavior.ALWAYS_CREATE_NEW_UUID;
}
public Copy<T> and( Location from ) {
@@ -5809,38 +5844,61 @@
/**
* Submit any requests to move the targets into the supplied parent location
*
+ * @param fromWorkspaceName the name of the workspace containing the {@code from} locations
* @param from the locations that are being copied
* @param into the parent location
* @param nameForCopy the name that should be used for the copy, or null if the name should be the same as the original
* @return this object, for method chaining
*/
- protected abstract T submit( Locations from,
- Location into,
- Name nameForCopy );
+ protected abstract T submit( String fromWorkspaceName,
+ Locations from,
+ Location into,
+ Name nameForCopy );
+ public FromWorkspace<CopyTarget<T>> failingIfUuidsMatch() {
+ this.uuidConflictBehavior = UuidConflictBehavior.THROW_EXCEPTION;
+ return this;
+ }
+
+ public FromWorkspace<CopyTarget<T>> removingMatchingUuids() {
+ this.uuidConflictBehavior = UuidConflictBehavior.REPLACE_EXISTING_NODE;
+ return this;
+ }
+
+ public FromWorkspace<CopyTarget<T>> unlessMatchingUuidExists() {
+ this.uuidConflictBehavior = UuidConflictBehavior.DO_NOT_COPY;
+ return this;
+ }
+
+ public CopyTarget<T> fromWorkspace( String workspaceName ) {
+ this.fromWorkspaceName = workspaceName;
+
+ return this;
+ }
+
public T into( Location into ) {
- return submit(from, into, null);
+ return submit(this.fromWorkspaceName, this.from, into, null);
}
public T into( Path into ) {
- return submit(from, Location.create(into), null);
+ return submit(this.fromWorkspaceName, this.from, Location.create(into), null);
}
public T into( UUID into ) {
- return submit(from, Location.create(into), null);
+ return submit(this.fromWorkspaceName, this.from, Location.create(into), null);
}
public T into( Property firstIdProperty,
Property... additionalIdProperties ) {
- return submit(from, Location.create(firstIdProperty, additionalIdProperties), null);
+ return submit(this.fromWorkspaceName, this.from, Location.create(firstIdProperty, additionalIdProperties), null);
}
public T into( Property into ) {
- return submit(from, Location.create(into), null);
+ return submit(this.fromWorkspaceName, this.from, Location.create(into), null);
}
public T into( String into ) {
- return submit(from, Location.create(createPath(into)), null);
+ return submit(this.fromWorkspaceName, this.from, Location.create(createPath(into)), null);
}
public T to( Location desiredLocation ) {
@@ -5852,7 +5910,7 @@
throw new IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from, desiredLocation));
}
Path parent = desiredPath.getParent();
- return submit(from, Location.create(parent), desiredPath.getLastSegment().getName());
+ return submit(this.fromWorkspaceName, this.from, Location.create(parent), desiredPath.getLastSegment().getName());
}
public T to( Path desiredPath ) {
@@ -5860,7 +5918,7 @@
throw new IllegalArgumentException(GraphI18n.unableToCopyToTheRoot.text(this.from, desiredPath));
}
Path parent = desiredPath.getParent();
- return submit(from, Location.create(parent), desiredPath.getLastSegment().getName());
+ return submit(this.fromWorkspaceName, this.from, Location.create(parent), desiredPath.getLastSegment().getName());
}
public T to( String desiredPath ) {
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-13 15:56:00 UTC (rev 1049)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ForkRequestProcessor.java 2009-06-14 22:58:57 UTC (rev 1050)
@@ -1262,7 +1262,8 @@
// Create the pushed-down request ...
CopyBranchRequest pushDown = new CopyBranchRequest(fromProxy.location(), fromProxy.workspaceName(), intoProxy.location(),
intoProxy.workspaceName(), request.desiredName(),
- request.conflictBehavior());
+ 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/request/BatchRequestBuilder.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-06-13 15:56:00 UTC (rev 1049)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-06-14 22:58:57 UTC (rev 1050)
@@ -572,7 +572,8 @@
String intoWorkspace,
Name nameForCopy ) {
return add(new CopyBranchRequest(from, fromWorkspace, into, intoWorkspace, nameForCopy,
- CopyBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
+ CopyBranchRequest.DEFAULT_NODE_CONFLICT_BEHAVIOR,
+ UuidConflictBehavior.ALWAYS_CREATE_NEW_UUID));
}
/**
@@ -585,7 +586,10 @@
* @param nameForCopy the desired name for the node that results from the copy, or null if the name of the original should be
* used
* @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
- * location, or null if the default conflict behavior should be used
+ * location, or null if the default node conflict behavior should be used
+ * @param uuidConflictBehavior the expected behavior if a node with the same UUID as any of the nodes in the branch under the
+ * {@code from} location in the {@code fromWorkspace} workspace already exists in the workspace, or null if the default
+ * UUID conflict behavior should be used
* @return this builder for method chaining; never null
* @throws IllegalArgumentException if either of the locations or workspace names are null
*/
@@ -594,9 +598,12 @@
Location into,
String intoWorkspace,
Name nameForCopy,
- NodeConflictBehavior conflictBehavior ) {
- if (conflictBehavior == null) conflictBehavior = CopyBranchRequest.DEFAULT_CONFLICT_BEHAVIOR;
- return add(new CopyBranchRequest(from, fromWorkspace, into, intoWorkspace, nameForCopy, conflictBehavior));
+ NodeConflictBehavior conflictBehavior,
+ UuidConflictBehavior uuidConflictBehavior) {
+ if (conflictBehavior == null) conflictBehavior = CopyBranchRequest.DEFAULT_NODE_CONFLICT_BEHAVIOR;
+ if (uuidConflictBehavior == null) uuidConflictBehavior = CopyBranchRequest.DEFAULT_UUID_CONFLICT_BEHAVIOR;
+ return add(new CopyBranchRequest(from, fromWorkspace, into, intoWorkspace, nameForCopy, conflictBehavior,
+ uuidConflictBehavior));
}
/**
@@ -628,7 +635,8 @@
Location into,
String workspaceName,
Name newNameForNode ) {
- return add(new MoveBranchRequest(from, into, null, workspaceName, newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
+ return add(new MoveBranchRequest(from, into, null, workspaceName, newNameForNode,
+ MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
}
/**
@@ -647,7 +655,8 @@
Location before,
String workspaceName,
Name newNameForNode ) {
- return add(new MoveBranchRequest(from, into, before, workspaceName, newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
+ return add(new MoveBranchRequest(from, into, before, workspaceName, newNameForNode,
+ MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
}
/**
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java 2009-06-13 15:56:00 UTC (rev 1049)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/CopyBranchRequest.java 2009-06-14 22:58:57 UTC (rev 1050)
@@ -41,14 +41,16 @@
private static final long serialVersionUID = 1L;
- public static final NodeConflictBehavior DEFAULT_CONFLICT_BEHAVIOR = NodeConflictBehavior.APPEND;
+ public static final NodeConflictBehavior DEFAULT_NODE_CONFLICT_BEHAVIOR = NodeConflictBehavior.APPEND;
+ public static final UuidConflictBehavior DEFAULT_UUID_CONFLICT_BEHAVIOR = UuidConflictBehavior.ALWAYS_CREATE_NEW_UUID;
private final Location from;
private final Location into;
private final String fromWorkspace;
private final String intoWorkspace;
private final Name desiredNameForCopy;
- private final NodeConflictBehavior conflictBehavior;
+ private final NodeConflictBehavior nodeConflictBehavior;
+ private final UuidConflictBehavior uuidConflictBehavior;
private Location actualFromLocation;
private Location actualIntoLocation;
@@ -66,7 +68,7 @@
String fromWorkspace,
Location into,
String intoWorkspace ) {
- this(from, fromWorkspace, into, intoWorkspace, null, DEFAULT_CONFLICT_BEHAVIOR);
+ this(from, fromWorkspace, into, intoWorkspace, null, DEFAULT_NODE_CONFLICT_BEHAVIOR, DEFAULT_UUID_CONFLICT_BEHAVIOR);
}
/**
@@ -85,7 +87,7 @@
Location into,
String intoWorkspace,
Name nameForCopy ) {
- this(from, fromWorkspace, into, intoWorkspace, nameForCopy, DEFAULT_CONFLICT_BEHAVIOR);
+ this(from, fromWorkspace, into, intoWorkspace, nameForCopy, DEFAULT_NODE_CONFLICT_BEHAVIOR, DEFAULT_UUID_CONFLICT_BEHAVIOR);
}
/**
@@ -97,8 +99,10 @@
* @param intoWorkspace the name of the workspace where the <code>into</code> node is to be copied
* @param nameForCopy the desired name for the node that results from the copy, or null if the name of the original should be
* used
- * @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
+ * @param nodeConflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
* location
+ * @param uuidConflictBehavior the expected behavior if a node with the same UUID as any of the nodes in the branch under the
+ * {@code from} location in the {@code fromWorkspace} workspace already exists in the workspace
* @throws IllegalArgumentException if any of the parameters are null
*/
public CopyBranchRequest( Location from,
@@ -106,18 +110,21 @@
Location into,
String intoWorkspace,
Name nameForCopy,
- NodeConflictBehavior conflictBehavior ) {
+ NodeConflictBehavior nodeConflictBehavior,
+ UuidConflictBehavior uuidConflictBehavior ) {
CheckArg.isNotNull(from, "from");
CheckArg.isNotNull(into, "into");
CheckArg.isNotNull(fromWorkspace, "fromWorkspace");
CheckArg.isNotNull(intoWorkspace, "intoWorkspace");
- CheckArg.isNotNull(conflictBehavior, "conflictBehavior");
+ CheckArg.isNotNull(nodeConflictBehavior, "nodeConflictBehavior");
+ CheckArg.isNotNull(uuidConflictBehavior, "uuidConflictBehavior");
this.from = from;
this.into = into;
this.fromWorkspace = fromWorkspace;
this.intoWorkspace = intoWorkspace;
this.desiredNameForCopy = nameForCopy;
- this.conflictBehavior = conflictBehavior;
+ this.nodeConflictBehavior = nodeConflictBehavior;
+ this.uuidConflictBehavior = uuidConflictBehavior;
}
/**
@@ -191,11 +198,20 @@
*
* @return the behavior specification
*/
- public NodeConflictBehavior conflictBehavior() {
- return conflictBehavior;
+ public NodeConflictBehavior nodeConflictBehavior() {
+ return nodeConflictBehavior;
}
/**
+ * Get the expected behavior when one of the nodes in the branch has the same UUID as an existing node in the workspace.
+ *
+ * @return the behavior specification
+ */
+ public UuidConflictBehavior uuidConflictBehavior() {
+ return uuidConflictBehavior;
+ }
+
+ /**
* Sets the actual and complete location of the node being renamed and its new location. This method must be called when
* processing the request, and the actual location must have a {@link Location#getPath() path}.
*
@@ -313,7 +329,7 @@
CopyBranchRequest that = (CopyBranchRequest)obj;
if (!this.from().equals(that.from())) return false;
if (!this.into().equals(that.into())) return false;
- if (!this.conflictBehavior().equals(that.conflictBehavior())) return false;
+ if (!this.nodeConflictBehavior().equals(that.nodeConflictBehavior())) return false;
if (!this.fromWorkspace.equals(that.fromWorkspace)) return false;
if (!this.intoWorkspace.equals(that.intoWorkspace)) return false;
return true;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java 2009-06-13 15:56:00 UTC (rev 1049)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java 2009-06-14 22:58:57 UTC (rev 1050)
@@ -432,6 +432,8 @@
* used
* @param conflictBehavior the expected behavior if an equivalently-named child already exists at the <code>into</code>
* location, or null if the default conflict behavior should be used
+ * @param uuidConflictBehavior the expected behavior if a node with the same UUID as any of the nodes in the branch under the
+ * {@code from} location in the {@code fromWorkspace} workspace already exists in the workspace
* @return the request; never null
* @throws IllegalArgumentException if either of the locations or workspace names are null
*/
@@ -440,9 +442,11 @@
Location into,
String intoWorkspace,
Name nameForCopy,
- NodeConflictBehavior conflictBehavior ) {
- if (conflictBehavior == null) conflictBehavior = CopyBranchRequest.DEFAULT_CONFLICT_BEHAVIOR;
- return process(new CopyBranchRequest(from, fromWorkspace, into, intoWorkspace, nameForCopy, conflictBehavior));
+ NodeConflictBehavior conflictBehavior,
+ UuidConflictBehavior uuidConflictBehavior) {
+ if (conflictBehavior == null) conflictBehavior = CopyBranchRequest.DEFAULT_NODE_CONFLICT_BEHAVIOR;
+ return process(new CopyBranchRequest(from, fromWorkspace, into, intoWorkspace, nameForCopy, conflictBehavior,
+ uuidConflictBehavior));
}
/**
@@ -474,9 +478,10 @@
Location into,
String workspaceName,
Name newNameForNode ) {
- return process(new MoveBranchRequest(from, into, null, workspaceName, newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
+ return process(new MoveBranchRequest(from, into, null, workspaceName, newNameForNode,
+ MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
}
-
+
/**
* Create a request to move a branch from one location into another before the given child node of the new location.
*
@@ -490,11 +495,13 @@
*/
public MoveBranchRequest moveBranch( Location from,
Location into,
- Location before,
+ Location before,
String workspaceName,
Name newNameForNode ) {
- return process(new MoveBranchRequest(from, into, before, workspaceName, newNameForNode, MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
- }
+ return process(new MoveBranchRequest(from, into, before, workspaceName, newNameForNode,
+ MoveBranchRequest.DEFAULT_CONFLICT_BEHAVIOR));
+ }
+
/**
* Create a request to move a branch from one location into another.
*
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java 2009-06-13 15:56:00 UTC (rev 1049)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java 2009-06-14 22:58:57 UTC (rev 1050)
@@ -72,6 +72,7 @@
import org.jboss.dna.graph.request.Request;
import org.jboss.dna.graph.request.SetPropertyRequest;
import org.jboss.dna.graph.request.UpdatePropertiesRequest;
+import org.jboss.dna.graph.request.UuidConflictBehavior;
import org.jboss.dna.graph.request.VerifyNodeExistsRequest;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest.CloneConflictBehavior;
@@ -184,13 +185,28 @@
protected void assertNextRequestIsCopy( Location from,
Location to ) {
+ assertNextRequestIsCopy(this.graph.getCurrentWorkspaceName(), from, to);
+ }
+
+ protected void assertNextRequestIsCopy( String fromWorkspace,
+ Location from,
+ Location to ) {
+ assertNextRequestIsCopy(fromWorkspace, from, to, UuidConflictBehavior.ALWAYS_CREATE_NEW_UUID);
+ }
+
+ protected void assertNextRequestIsCopy( String fromWorkspace,
+ Location from,
+ Location to,
+ UuidConflictBehavior uuidConflictBehavior) {
Request request = executedRequests.poll();
assertThat(request, is(instanceOf(CopyBranchRequest.class)));
CopyBranchRequest copy = (CopyBranchRequest)request;
+ assertThat(copy.fromWorkspace(), is(fromWorkspace));
assertThat(copy.from(), is(from));
assertThat(copy.into(), is(to));
+ assertThat(copy.uuidConflictBehavior(), is(uuidConflictBehavior));
}
-
+
protected void assertNextRequestIsDelete( Location at ) {
Request request = executedRequests.poll();
assertThat(request, is(instanceOf(DeleteBranchRequest.class)));
@@ -377,6 +393,24 @@
}
@Test
+ public void shouldCopyNodeFromOtherWorkspace() {
+ graph.copy(validPath).fromWorkspace("other").into(validIdProperty1, validIdProperty2);
+ assertThat(numberOfExecutions, is(1));
+ assertNextRequestIsCopy("other", Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
+ assertNoMoreRequests();
+
+ graph.copy(validPathString).into(validIdProperty1, validIdProperty2);
+ assertThat(numberOfExecutions, is(1));
+ assertNextRequestIsCopy(Location.create(validPath), Location.create(validIdProperty1, validIdProperty2));
+ assertNoMoreRequests();
+
+ graph.copy(validUuid).into(validPath);
+ assertThat(numberOfExecutions, is(1));
+ assertNextRequestIsCopy(Location.create(validUuid), Location.create(validPath));
+ assertNoMoreRequests();
+ }
+
+ @Test
public void shouldDeleteNode() {
graph.delete(validPath);
assertThat(numberOfExecutions, is(1));
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-13 15:56:00 UTC (rev 1049)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-06-14 22:58:57 UTC (rev 1050)
@@ -28,6 +28,7 @@
import java.security.AccessControlException;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import javax.jcr.AccessDeniedException;
import javax.jcr.InvalidSerializedDataException;
import javax.jcr.ItemExistsException;
@@ -53,6 +54,7 @@
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.RepositorySourceException;
import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.Property;
@@ -270,9 +272,25 @@
String destAbsPath )
throws ConstraintViolationException, VersionException, AccessDeniedException, PathNotFoundException, ItemExistsException,
LockException, RepositoryException {
- CheckArg.isNotEmpty(srcAbsPath, "srcAbsPath");
- CheckArg.isNotEmpty(destAbsPath, "destAbsPath");
+ this.copy(this.name, srcAbsPath, destAbsPath);
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public void copy( String srcWorkspace,
+ String srcAbsPath,
+ String destAbsPath )
+ 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;
@@ -294,8 +312,7 @@
}
try {
- // this.session.checkPermission(srcAbsPath.substring(0, srcAbsPath.lastIndexOf('/')), "remove");
- this.session.checkPermission(destAbsPath, "add_node");
+ this.session.checkPermission(destPath.getParent(), "add_node");
}
catch (AccessControlException ace) {
throw new AccessDeniedException(ace);
@@ -305,7 +322,6 @@
* Make sure that the node has a definition at the new location
*/
SessionCache cache = this.session.cache();
- NodeInfo nodeInfo = cache.findNodeInfo(null, srcPath);
NodeInfo cacheParent = cache.findNodeInfo(null, destPath.getParent());
// Skip the cache and load the latest parent info directly from the graph
@@ -314,30 +330,22 @@
String parentPath = destPath.getParent().getString(this.context.getNamespaceRegistry());
// This will check for a definition and throw a ConstraintViolationException or ItemExistsException if none is found
- this.session.cache().findBestNodeDefinition(parent, parentPath, newNodeName, nodeInfo.getPrimaryTypeName());
+ graph.useWorkspace(srcWorkspace);
+ Property primaryTypeProp = graph.getNodeAt(srcPath).getProperty(JcrLexicon.PRIMARY_TYPE);
+ Property uuidProp = graph.getNodeAt(srcPath).getProperty(DnaLexicon.UUID);
+ 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).to(destPath);
- cache.compensateForWorkspaceChildChange(cacheParent.getUuid(), null, nodeInfo.getUuid(), newNodeName);
-
- }
-
- /**
- * {@inheritDoc}
- */
- public void copy( String srcWorkspace,
- String srcAbsPath,
- String destAbsPath ) throws NoSuchWorkspaceException {
- CheckArg.isNotNull(srcWorkspace, "source workspace");
- CheckArg.isNotNull(srcAbsPath, "source path");
- CheckArg.isNotNull(destAbsPath, "destination path");
+ graph.copy(srcPath).fromWorkspace(srcWorkspace).to(destPath);
- if (!graph.getWorkspaces().contains(srcWorkspace)) {
- throw new NoSuchWorkspaceException(JcrI18n.workspaceNameIsInvalid.text(graph.getSourceName(), this.name));
- }
-
-
- throw new UnsupportedOperationException();
+ // Load the node that we just copied
+ cache.compensateForWorkspaceChildChange(cacheParent.getUuid(), null, UUID.fromString(uuidProp.getFirstValue().toString()), newNodeName);
}
/**
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java 2009-06-13 15:56:00 UTC (rev 1049)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/DnaTckTest.java 2009-06-14 22:58:57 UTC (rev 1050)
@@ -9,7 +9,6 @@
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import org.apache.jackrabbit.test.AbstractJCRTest;
-import org.junit.Test;
/**
* Additional DNA tests that check for JCR compliance.
@@ -141,7 +140,6 @@
* Tests that read-write sessions can read nodes by loading all of the children of the root node
* @throws Exception
*/
- @Test
public void testShouldAllowReadWriteSessionToRead() throws Exception {
session = helper.getReadWriteSession();
testRead(session);
@@ -151,7 +149,6 @@
* Tests that read-write sessions can add nodes, remove nodes, set nodes, and set properties.
* @throws Exception
*/
- @Test
public void testShouldAllowReadWriteSessionToWrite() throws Exception {
session = helper.getReadWriteSession();
testWrite(session);
@@ -162,7 +159,6 @@
* workspace. This test makes sure both work.
* @throws Exception
*/
- @Test
public void testShouldMapRolesToWorkspacesWhenSpecified() throws Exception {
Credentials creds = new SimpleCredentials("defaultonly", "defaultonly".toCharArray());
session = helper.getRepository().login(creds);
@@ -183,4 +179,24 @@
session.logout();
}
+
+ public void testShouldCopyFromAnotherWorkspace() throws Exception {
+ session = helper.getSuperuserSession("otherWorkspace");
+ String nodetype1 = this.getProperty("nodetype");
+ Node node1 = session.getRootNode().addNode(nodeName1, nodetype1);
+ node1.addNode(nodeName2, nodetype1);
+ session.save();
+ session.logout();
+
+ superuser.getRootNode().addNode(nodeName4, nodetype1);
+ superuser.save();
+
+ superuser.getWorkspace().copy("otherWorkspace", "/" + nodeName1, "/" + nodeName4 + "/" + nodeName1);
+
+ Node node4 = superuser.getRootNode().getNode(nodeName4);
+ Node node4node1 = node4.getNode(nodeName1);
+ Node node4node1node2 = node4node1.getNode(nodeName2);
+
+ assertNotNull(node4node1node2);
+ }
}
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-13 15:56:00 UTC (rev 1049)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrWorkspaceTest.java 2009-06-14 22:58:57 UTC (rev 1050)
@@ -98,6 +98,7 @@
Graph graph = Graph.create(source, context);
graph.create("/a").and().create("/a/b").and().create("/a/b/c").and().create("/b");
graph.set("booleanProperty").on("/a/b").to(true);
+ graph.set("jcr:primaryType").on("/a/b").to("nt:unstructured");
graph.set("stringProperty").on("/a/b/c").to("value");
// Make sure the path to the namespaces exists ...
Modified: trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java
===================================================================
--- trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java 2009-06-13 15:56:00 UTC (rev 1049)
+++ trunk/extensions/dna-connector-federation/src/main/java/org/jboss/dna/connector/federation/FederatingRequestProcessor.java 2009-06-14 22:58:57 UTC (rev 1050)
@@ -367,7 +367,8 @@
Location intoLocation = Location.create(intoProjection.pathInSource);
String workspaceName = fromProjection.projection.getWorkspaceName();
CopyBranchRequest sourceRequest = new CopyBranchRequest(fromLocation, workspaceName, intoLocation, workspaceName,
- request.desiredName(), request.conflictBehavior());
+ request.desiredName(), request.nodeConflictBehavior(),
+ request.uuidConflictBehavior());
execute(sourceRequest, fromProjection.projection);
// Copy/transform the results ...
14 years, 10 months
DNA SVN: r1049 - in trunk/dna-jcr/src: main/resources/org/jboss/dna/jcr and 1 other directories.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-06-13 11:56:00 -0400 (Sat, 13 Jun 2009)
New Revision: 1049
Modified:
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/JcrNodeType.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java
trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java
Log:
Committed most of unregisterTypes method. Still need to add check that the type is not in use on any nodes, but this should be much easier after queries are implemented. Leaving this open until that piece of the issue is corrected.
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-12 01:28:17 UTC (rev 1048)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrI18n.java 2009-06-13 15:56:00 UTC (rev 1049)
@@ -115,6 +115,7 @@
// Type registration messages
public static I18n invalidNodeTypeName;
+ public static I18n noSuchNodeType;
public static I18n nodeTypeAlreadyExists;
public static I18n invalidPrimaryTypeName;
public static I18n invalidSupertypeName;
@@ -139,6 +140,10 @@
public static I18n nodeNotReferenceable;
public static I18n noPendingChangesAllowed;
+ public static I18n cannotUnregisterSupertype;
+ public static I18n cannotUnregisterRequiredPrimaryType;
+ public static I18n cannotUnregisterDefaultPrimaryType;
+
static {
try {
I18n.initialize(JcrI18n.class);
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-12 01:28:17 UTC (rev 1048)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNode.java 2009-06-13 15:56:00 UTC (rev 1049)
@@ -94,5 +94,4 @@
public void remove() throws RepositoryException {
editorForParent().destroyChild(nodeUuid);
}
-
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-06-12 01:28:17 UTC (rev 1048)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeType.java 2009-06-13 15:56:00 UTC (rev 1049)
@@ -165,6 +165,10 @@
return thisAndAllSupertypes;
}
+ List<JcrNodeType> supertypes() {
+ return allSupertypes;
+ }
+
/**
* Get the child definitions defined on this node type (excluding inherited definitions).
*
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java 2009-06-12 01:28:17 UTC (rev 1048)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrNodeTypeManager.java 2009-06-13 15:56:00 UTC (rev 1049)
@@ -39,6 +39,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.NameFactory;
import org.jboss.dna.jcr.nodetype.InvalidNodeTypeDefinitionException;
import org.jboss.dna.jcr.nodetype.NodeDefinitionTemplate;
import org.jboss.dna.jcr.nodetype.NodeTypeDefinition;
@@ -416,6 +417,32 @@
}
/**
+ * Allows the collection of node types to be unregistered if they are not referenced by other node types as supertypes,
+ * default primary types of child nodes, or required primary types of child nodes.
+ * <p>
+ * <b>NOTE: This method does not check to see if any of the node types are currently being used. Unregistering a node type
+ * that is being used will cause the system to become unstable</b>
+ * </p>
+ *
+ * @param nodeTypeNames the names of the node types to be unregistered
+ * @throws NoSuchNodeTypeException if any of the node type names do not correspond to a registered node type
+ * @throws InvalidNodeTypeDefinitionException if any of the node types with the given names cannot be unregistered because
+ * they are the supertype, one of the required primary types, or a default primary type of a node type that is not
+ * being unregistered.
+ * @throws RepositoryException if any other error occurs
+ */
+ public void unregisterNodeType( Collection<String> nodeTypeNames )
+ throws NoSuchNodeTypeException, InvalidNodeTypeDefinitionException, RepositoryException {
+ NameFactory nameFactory = this.context.getValueFactories().getNameFactory();
+
+ Collection<Name> names = new ArrayList<Name>(nodeTypeNames.size());
+ for (String name : nodeTypeNames) {
+ names.add(nameFactory.create(name));
+ }
+ repositoryTypeManager.unregisterNodeType(names);
+ }
+
+ /**
* Returns an empty {@code NodeTypeTemplate} which can then be used to define a node type and passed to
* {@link JcrNodeTypeManager#registerNodeType(NodeTypeDefinition, boolean)}
*
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java 2009-06-12 01:28:17 UTC (rev 1048)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/RepositoryNodeTypeManager.java 2009-06-13 15:56:00 UTC (rev 1049)
@@ -38,6 +38,7 @@
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.PropertyDefinition;
@@ -46,6 +47,7 @@
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.text.TextEncoder;
import org.jboss.dna.common.text.XmlNameEncoder;
+import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
import org.jboss.dna.graph.Location;
@@ -1100,6 +1102,89 @@
}
/**
+ * Allows the collection of node types to be unregistered if they are not referenced by other node types as supertypes,
+ * default primary types of child nodes, or required primary types of child nodes.
+ * <p>
+ * <b>NOTE: This method does not check to see if any of the node types are currently being used. Unregistering a node type
+ * that is being used will cause the system to become unstable</b>
+ * </p>
+ *
+ * @param nodeTypeNames the names of the node types to be unregistered
+ * @throws NoSuchNodeTypeException if any of the node type names do not correspond to a registered node type
+ * @throws InvalidNodeTypeDefinitionException if any of the node types with the given names cannot be unregistered because
+ * they are the supertype, one of the required primary types, or a default primary type of a node type that is not
+ * being unregistered.
+ * @throws RepositoryException if any other error occurs
+ */
+ void unregisterNodeType( Collection<Name> nodeTypeNames )
+ throws NoSuchNodeTypeException, InvalidNodeTypeDefinitionException, RepositoryException {
+ CheckArg.isNotNull(nodeTypeNames, "nodeTypeNames");
+ try {
+ /*
+ * Grab an exclusive lock on this data to keep other nodes from being added/saved while the unregistration checks are occurring
+ */
+ nodeTypeManagerLock.writeLock().lock();
+
+ for (Name nodeTypeName : nodeTypeNames) {
+ /*
+ * Check that the type names are valid
+ */
+ if (nodeTypeName == null) {
+ throw new NoSuchNodeTypeException(JcrI18n.invalidNodeTypeName.text());
+ }
+ String name = nodeTypeName.getString(context.getNamespaceRegistry());
+
+ if (!this.nodeTypes.containsKey(nodeTypeName)) {
+ throw new NoSuchNodeTypeException(JcrI18n.noSuchNodeType.text(name));
+ }
+
+ /*
+ * Check that no other node definitions have dependencies on any of the named types
+ */
+ for (JcrNodeType nodeType : nodeTypes.values()) {
+ // If this node is also being unregistered, don't run checks against it
+ if (nodeTypeNames.contains(nodeType.getInternalName())) {
+ continue;
+ }
+
+ for (JcrNodeType supertype : nodeType.supertypes()) {
+ if (nodeTypeName.equals(supertype.getInternalName())) {
+ throw new InvalidNodeTypeDefinitionException(
+ JcrI18n.cannotUnregisterSupertype.text(name,
+ supertype.getName()));
+ }
+ }
+
+ for (JcrNodeDefinition childNode : nodeType.childNodeDefinitions()) {
+ NodeType defaultPrimaryType = childNode.getDefaultPrimaryType();
+ if (defaultPrimaryType != null && name.equals(defaultPrimaryType.getName())) {
+ throw new InvalidNodeTypeDefinitionException(
+ JcrI18n.cannotUnregisterDefaultPrimaryType.text(name,
+ nodeType.getName(),
+ childNode.getName()));
+ }
+ if (childNode.getRequiredPrimaryTypeNames().contains(nodeTypeName)) {
+ throw new InvalidNodeTypeDefinitionException(
+ JcrI18n.cannotUnregisterRequiredPrimaryType.text(name,
+ nodeType.getName(),
+ childNode.getName()));
+ }
+ }
+ }
+ }
+
+ /*
+ * Do a full recursive search over the content graph to make sure that this type isn't being used
+ */
+ // TODO: replace this with a query after queries work
+ this.nodeTypes.keySet().removeAll(nodeTypeNames);
+
+ } finally {
+ nodeTypeManagerLock.writeLock().unlock();
+ }
+ }
+
+ /**
* Registers a new node type or updates an existing node type using the specified definition and returns the resulting {@code
* NodeType} object.
* <p>
@@ -1803,15 +1888,13 @@
for (JcrNodeDefinition ancestor : ancestors) {
if (ancestor.isProtected()) {
throw new InvalidNodeTypeDefinitionException(
- JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType()
- .getName(),
+ JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType().getName(),
"child node"));
}
if (ancestor.isMandatory() && !node.isMandatory()) {
throw new InvalidNodeTypeDefinitionException(
- JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType()
- .getName(),
+ JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType().getName(),
"child node"));
}
@@ -1876,16 +1959,15 @@
Value[] defaultValues = prop.getDefaultValues();
if (prop.isAutoCreated() && !prop.isProtected() && (defaultValues == null || defaultValues.length == 0)) {
- throw new InvalidNodeTypeDefinitionException(JcrI18n.autocreatedPropertyNeedsDefault.text(prop.getName(),
- prop.getDeclaringNodeType()
- .getName()));
+ throw new InvalidNodeTypeDefinitionException(
+ JcrI18n.autocreatedPropertyNeedsDefault.text(prop.getName(),
+ prop.getDeclaringNodeType().getName()));
}
if (!prop.isMultiple() && (defaultValues != null && defaultValues.length > 1)) {
throw new InvalidNodeTypeDefinitionException(
JcrI18n.singleValuedPropertyNeedsSingleValuedDefault.text(prop.getName(),
- prop.getDeclaringNodeType()
- .getName()));
+ prop.getDeclaringNodeType().getName()));
}
Name propName = context.getValueFactories().getNameFactory().create(prop.getName());
@@ -1899,15 +1981,13 @@
for (JcrPropertyDefinition ancestor : ancestors) {
if (ancestor.isProtected()) {
throw new InvalidNodeTypeDefinitionException(
- JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType()
- .getName(),
+ JcrI18n.cannotOverrideProtectedDefinition.text(ancestor.getDeclaringNodeType().getName(),
"property"));
}
if (ancestor.isMandatory() && !prop.isMandatory()) {
throw new InvalidNodeTypeDefinitionException(
- JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType()
- .getName(),
+ JcrI18n.cannotMakeMandatoryDefinitionOptional.text(ancestor.getDeclaringNodeType().getName(),
"property"));
}
@@ -1918,16 +1998,14 @@
&& !Arrays.equals(ancestor.getValueConstraints(), prop.getValueConstraints())) {
throw new InvalidNodeTypeDefinitionException(
JcrI18n.constraintsChangedInSubtype.text(propName,
- ancestor.getDeclaringNodeType()
- .getName()));
+ ancestor.getDeclaringNodeType().getName()));
}
if (!isAlwaysSafeConversion(prop.getRequiredType(), ancestor.getRequiredType())) {
throw new InvalidNodeTypeDefinitionException(
JcrI18n.cannotRedefineProperty.text(propName,
PropertyType.nameFromValue(prop.getRequiredType()),
- ancestor.getDeclaringNodeType()
- .getName(),
+ ancestor.getDeclaringNodeType().getName(),
PropertyType.nameFromValue(ancestor.getRequiredType())));
}
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-12 01:28:17 UTC (rev 1048)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/JcrI18n.properties 2009-06-13 15:56:00 UTC (rev 1049)
@@ -100,6 +100,7 @@
invalidQueryLanguage="{0}" is not a valid query langauge. Supported languages are\: {1}
invalidNodeTypeName=Node types cannot have a null or empty name
+noSuchNodeType=Type named '{0}' does not exist
nodeTypeAlreadyExists=Node type '{0}' already exists
invalidPrimaryTypeName=Required primary type '{0}' in type '{1}' does not exist
invalidSupertypeName=Supertype '{0}' from type '{1}' does not exist
@@ -123,3 +124,7 @@
nodeNotReferenceable=Only referenceable nodes may be the value of reference properties
noPendingChangesAllowed=This operation cannot be performed when the session has pending changes
+
+cannotUnregisterSupertype=Cannot unregister type '{0}' which is supertype of type '{1}'
+cannotUnregisterRequiredPrimaryType=Cannot unregister type '{0}' which is the required primary type for child node '{2}' on type '{1}'
+cannotUnregisterDefaultPrimaryType=Cannot unregister type '{0}' which is the default primary type for child node '{2}' of type '{1}'
\ No newline at end of file
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java 2009-06-12 01:28:17 UTC (rev 1048)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/TypeRegistrationTest.java 2009-06-13 15:56:00 UTC (rev 1049)
@@ -25,12 +25,15 @@
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.PropertyDefinition;
import org.jboss.dna.graph.ExecutionContext;
@@ -41,6 +44,7 @@
import org.jboss.dna.jcr.nodetype.NodeDefinitionTemplate;
import org.jboss.dna.jcr.nodetype.NodeTypeDefinition;
import org.jboss.dna.jcr.nodetype.NodeTypeExistsException;
+import org.jboss.dna.jcr.nodetype.NodeTypeTemplate;
import org.jboss.dna.jcr.nodetype.PropertyDefinitionTemplate;
import org.junit.Before;
import org.junit.Test;
@@ -703,6 +707,103 @@
compareTemplatesToNodeTypes(templates, repoTypeManager.registerNodeTypes(templates, false));
}
+ /*
+ * Unregistration tests
+ */
+
+ @Test (expected=IllegalArgumentException.class)
+ public void shouldNotAllowUnregisteringNullCollection() throws Exception {
+ repoTypeManager.unregisterNodeType(null);
+ }
+
+ @Test (expected=NoSuchNodeTypeException.class)
+ public void shouldNotAllowUnregisteringInvalidTypeNames() throws Exception {
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { JcrNtLexicon.FILE, JcrLexicon.DATA}));
+ }
+
+ @Test (expected=InvalidNodeTypeDefinitionException.class)
+ public void shouldNotAllowUnregisteringSupertype() throws Exception {
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { JcrNtLexicon.HIERARCHY_NODE, }));
+
+ }
+
+ @Test (expected=InvalidNodeTypeDefinitionException.class)
+ public void shouldNotAllowUnregisteringRequiredPrimaryType() throws Exception {
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { JcrNtLexicon.FROZEN_NODE, }));
+ }
+
+ @Test (expected=InvalidNodeTypeDefinitionException.class)
+ public void shouldNotAllowUnregisteringDefaultPrimaryType() throws Exception {
+ ntTemplate.setName(TEST_TYPE_NAME);
+
+ JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
+ childNode.setDefaultPrimaryType(JcrNtLexicon.FILE.getString(this.registry));
+ ntTemplate.getNodeDefinitionTemplates().add(childNode);
+
+ try {
+ repoTypeManager.registerNodeType(ntTemplate, false);
+ }
+ catch (Exception ex) {
+ fail(ex.getMessage());
+ }
+
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { JcrNtLexicon.FILE, }));
+ }
+
+ @Test
+ public void shouldAllowUnregisteringUnusedType() throws Exception {
+ ntTemplate.setName(TEST_TYPE_NAME);
+
+ JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
+ childNode.setDefaultPrimaryType(JcrNtLexicon.FILE.getString(this.registry));
+ ntTemplate.getNodeDefinitionTemplates().add(childNode);
+
+ try {
+ repoTypeManager.registerNodeType(ntTemplate, false);
+ }
+ catch (Exception ex) {
+ fail(ex.getMessage());
+ }
+
+ Name typeNameAsName = nameFactory.create(TEST_TYPE_NAME);
+ int nodeTypeCount = repoTypeManager.getAllNodeTypes().size();
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { typeNameAsName }));
+ assertThat(repoTypeManager.getAllNodeTypes().size(), is(nodeTypeCount - 1));
+ assertThat(repoTypeManager.getNodeType(typeNameAsName), is(nullValue()));
+ }
+
+ @Test
+ public void shouldAllowUnregisteringUnusedTypesWithMutualDependencies() throws Exception {
+ ntTemplate.setName(TEST_TYPE_NAME);
+
+ JcrNodeDefinitionTemplate childNode = new JcrNodeDefinitionTemplate(this.context);
+ childNode.setDefaultPrimaryType(TEST_TYPE_NAME2);
+ ntTemplate.getNodeDefinitionTemplates().add(childNode);
+
+ NodeTypeTemplate ntTemplate2 = new JcrNodeTypeTemplate(this.context);
+ ntTemplate2.setName(TEST_TYPE_NAME2);
+
+ JcrNodeDefinitionTemplate childNode2 = new JcrNodeDefinitionTemplate(this.context);
+ childNode2.setDefaultPrimaryType(TEST_TYPE_NAME);
+ ntTemplate2.getNodeDefinitionTemplates().add(childNode2);
+
+ try {
+ repoTypeManager.registerNodeTypes(Arrays.asList(new NodeTypeDefinition[] { ntTemplate, ntTemplate2 }), false);
+ }
+ catch (Exception ex) {
+ fail(ex.getMessage());
+ }
+
+ Name typeNameAsName = nameFactory.create(TEST_TYPE_NAME);
+ Name type2NameAsName = nameFactory.create(TEST_TYPE_NAME2);
+ int nodeTypeCount = repoTypeManager.getAllNodeTypes().size();
+ repoTypeManager.unregisterNodeType(Arrays.asList(new Name[] { typeNameAsName, type2NameAsName }));
+ assertThat(repoTypeManager.getAllNodeTypes().size(), is(nodeTypeCount - 2));
+ assertThat(repoTypeManager.getNodeType(typeNameAsName), is(nullValue()));
+ assertThat(repoTypeManager.getNodeType(type2NameAsName), is(nullValue()));
+
+ }
+
private void compareTemplatesToNodeTypes( List<NodeTypeDefinition> templates,
List<JcrNodeType> nodeTypes ) {
assertThat(templates.size(), is(nodeTypes.size()));
@@ -826,4 +927,5 @@
// assertThat(template.getRequiredPrimaryTypeNames(), is(definition.getRequiredPrimaryTypeNames()));
}
+
}
14 years, 10 months
DNA SVN: r1048 - trunk/dna-jcr/src/main/java/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-06-11 21:28:17 -0400 (Thu, 11 Jun 2009)
New Revision: 1048
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java
Log:
Adding barely-there partial implementation of Workspace.copy(String,String,String) to repair build after DNA-399 checkin
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-12 01:07:00 UTC (rev 1047)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/JcrWorkspace.java 2009-06-12 01:28:17 UTC (rev 1048)
@@ -32,6 +32,7 @@
import javax.jcr.InvalidSerializedDataException;
import javax.jcr.ItemExistsException;
import javax.jcr.NamespaceRegistry;
+import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
@@ -326,7 +327,16 @@
*/
public void copy( String srcWorkspace,
String srcAbsPath,
- String destAbsPath ) {
+ String destAbsPath ) throws NoSuchWorkspaceException {
+ CheckArg.isNotNull(srcWorkspace, "source workspace");
+ 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));
+ }
+
+
throw new UnsupportedOperationException();
}
14 years, 11 months