Author: bcarothers
Date: 2009-10-30 17:34:28 -0400 (Fri, 30 Oct 2009)
New Revision: 1316
Modified:
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/JpaRepositoryTckTest.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/WorkspaceLockManager.java
trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/dna_builtins.cnd
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java
Log:
DNA-518 JPA connector fails to properly clone or update from another workspace
The previous patch fixed the originally declared issue, but exposed a few regressions. The
committed patch fixes most of those regressions and corrects a significant design flaw in
the original locking implementation (using jcr:uuid to refer to another nodes uuid).
However, this patch does not correct two key defects. JCR imports (session and workspace)
that include collisions with existing nodes that share a UUID will fail if the
removeExisting flag is set to true. There is also a minor defect with moving locked nodes
on this connector.
Since the original defect is addressed, this defect can be resolved and two new defects
can be opened for the other regressions.
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-10-29
21:25:06 UTC (rev 1315)
+++
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java 2009-10-30
21:34:28 UTC (rev 1316)
@@ -40,6 +40,7 @@
import org.jboss.dna.common.util.IoUtil;
import org.jboss.dna.graph.DnaLexicon;
import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.Node;
import org.jboss.dna.graph.Subgraph;
import org.jboss.dna.graph.connector.RepositorySource;
@@ -1020,7 +1021,16 @@
}
private UUID uuidFor( Node node ) {
- return (UUID)node.getProperty(DnaLexicon.UUID).getFirstValue();
+ UUID uuid = null;
+ if (node.getLocation().getUuid() != null) {
+ uuid = node.getLocation().getUuid();
+ }
+
+ if (uuid == null && (node.getProperty(JcrLexicon.UUID) != null)) {
+ uuid = (UUID)node.getProperty(JcrLexicon.UUID).getFirstValue();
+ }
+
+ return uuid;
}
protected void assertReference( String fromNodePath,
Modified:
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/JpaRepositoryTckTest.java
===================================================================
---
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/JpaRepositoryTckTest.java 2009-10-29
21:25:06 UTC (rev 1315)
+++
trunk/dna-integration-tests/src/test/java/org/jboss/dna/test/integration/JpaRepositoryTckTest.java 2009-10-30
21:34:28 UTC (rev 1316)
@@ -24,10 +24,147 @@
package org.jboss.dna.test.integration;
import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.jackrabbit.test.api.AddNodeTest;
+import org.apache.jackrabbit.test.api.CheckPermissionTest;
+import org.apache.jackrabbit.test.api.ImpersonateTest;
+import org.apache.jackrabbit.test.api.NamespaceRegistryTest;
+import org.apache.jackrabbit.test.api.NodeAddMixinTest;
+import org.apache.jackrabbit.test.api.NodeCanAddMixinTest;
+import org.apache.jackrabbit.test.api.NodeItemIsModifiedTest;
+import org.apache.jackrabbit.test.api.NodeItemIsNewTest;
+import org.apache.jackrabbit.test.api.NodeOrderableChildNodesTest;
+import org.apache.jackrabbit.test.api.NodeRemoveMixinTest;
+import org.apache.jackrabbit.test.api.NodeTest;
+import org.apache.jackrabbit.test.api.PropertyItemIsModifiedTest;
+import org.apache.jackrabbit.test.api.PropertyItemIsNewTest;
+import org.apache.jackrabbit.test.api.PropertyTest;
+import org.apache.jackrabbit.test.api.RepositoryLoginTest;
+import org.apache.jackrabbit.test.api.SerializationTest;
+import org.apache.jackrabbit.test.api.SessionTest;
+import org.apache.jackrabbit.test.api.SetPropertyAssumeTypeTest;
+import org.apache.jackrabbit.test.api.SetPropertyBooleanTest;
+import org.apache.jackrabbit.test.api.SetPropertyCalendarTest;
+import org.apache.jackrabbit.test.api.SetPropertyConstraintViolationExceptionTest;
+import org.apache.jackrabbit.test.api.SetPropertyDoubleTest;
+import org.apache.jackrabbit.test.api.SetPropertyInputStreamTest;
+import org.apache.jackrabbit.test.api.SetPropertyLongTest;
+import org.apache.jackrabbit.test.api.SetPropertyNodeTest;
+import org.apache.jackrabbit.test.api.SetPropertyStringTest;
+import org.apache.jackrabbit.test.api.SetPropertyValueTest;
+import org.apache.jackrabbit.test.api.SetValueBinaryTest;
+import org.apache.jackrabbit.test.api.SetValueBooleanTest;
+import org.apache.jackrabbit.test.api.SetValueConstraintViolationExceptionTest;
+import org.apache.jackrabbit.test.api.SetValueDateTest;
+import org.apache.jackrabbit.test.api.SetValueDoubleTest;
+import org.apache.jackrabbit.test.api.SetValueLongTest;
+import org.apache.jackrabbit.test.api.SetValueReferenceTest;
+import org.apache.jackrabbit.test.api.SetValueStringTest;
+import org.apache.jackrabbit.test.api.SetValueValueFormatExceptionTest;
+import org.apache.jackrabbit.test.api.SetValueVersionExceptionTest;
+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;
+import org.apache.jackrabbit.test.api.WorkspaceCopyBetweenWorkspacesTest;
+import org.apache.jackrabbit.test.api.WorkspaceCopyBetweenWorkspacesVersionableTest;
+import org.apache.jackrabbit.test.api.WorkspaceCopyReferenceableTest;
+import org.apache.jackrabbit.test.api.WorkspaceCopySameNameSibsTest;
+import org.apache.jackrabbit.test.api.WorkspaceCopyTest;
+import org.apache.jackrabbit.test.api.WorkspaceCopyVersionableTest;
+import org.apache.jackrabbit.test.api.WorkspaceMoveReferenceableTest;
+import org.apache.jackrabbit.test.api.WorkspaceMoveSameNameSibsTest;
+import org.apache.jackrabbit.test.api.WorkspaceMoveTest;
+import org.apache.jackrabbit.test.api.WorkspaceMoveVersionableTest;
public class JpaRepositoryTckTest {
public static Test suite() {
- return AbstractRepositoryTckTest.readWriteRepositorySuite("jpa");
+ TestSuite suite =
AbstractRepositoryTckTest.readOnlyRepositorySuite("jpa");
+ suite.addTest(new LevelTwoFeatureTests());
+ // suite.addTest(org.apache.jackrabbit.test.api.lock.TestAll.suite());
+
+ return suite;
+
}
+
+ private static class LevelTwoFeatureTests extends TestSuite {
+ protected LevelTwoFeatureTests() {
+ super("JCR Level 2 API Tests");
+ // We currently don't pass the tests in those suites that are commented
out
+ // See
https://jira.jboss.org/jira/browse/DNA-285
+
+ // level 2 tests
+ addTestSuite(AddNodeTest.class);
+ addTestSuite(NamespaceRegistryTest.class);
+ // addTestSuite(ReferencesTest.class);
+ addTestSuite(SessionTest.class);
+ // addTestSuite(SessionUUIDTest.class);
+ addTestSuite(NodeTest.class);
+ // addTestSuite(NodeUUIDTest.class);
+ addTestSuite(NodeOrderableChildNodesTest.class);
+ addTestSuite(PropertyTest.class);
+
+ addTestSuite(SetValueBinaryTest.class);
+ addTestSuite(SetValueBooleanTest.class);
+ addTestSuite(SetValueDateTest.class);
+ addTestSuite(SetValueDoubleTest.class);
+ addTestSuite(SetValueLongTest.class);
+ addTestSuite(SetValueReferenceTest.class);
+ addTestSuite(SetValueStringTest.class);
+ addTestSuite(SetValueConstraintViolationExceptionTest.class);
+ addTestSuite(SetValueValueFormatExceptionTest.class);
+ addTestSuite(SetValueVersionExceptionTest.class);
+
+ addTestSuite(SetPropertyBooleanTest.class);
+ addTestSuite(SetPropertyCalendarTest.class);
+ addTestSuite(SetPropertyDoubleTest.class);
+ addTestSuite(SetPropertyInputStreamTest.class);
+ addTestSuite(SetPropertyLongTest.class);
+ addTestSuite(SetPropertyNodeTest.class);
+ addTestSuite(SetPropertyStringTest.class);
+ addTestSuite(SetPropertyValueTest.class);
+ addTestSuite(SetPropertyConstraintViolationExceptionTest.class);
+ addTestSuite(SetPropertyAssumeTypeTest.class);
+
+ addTestSuite(NodeItemIsModifiedTest.class);
+ addTestSuite(NodeItemIsNewTest.class);
+ addTestSuite(PropertyItemIsModifiedTest.class);
+ addTestSuite(PropertyItemIsNewTest.class);
+
+ addTestSuite(NodeAddMixinTest.class);
+ addTestSuite(NodeCanAddMixinTest.class);
+ addTestSuite(NodeRemoveMixinTest.class);
+
+ addTestSuite(WorkspaceCloneReferenceableTest.class);
+ addTestSuite(WorkspaceCloneSameNameSibsTest.class);
+ addTestSuite(WorkspaceCloneTest.class);
+ addTestSuite(WorkspaceCloneVersionableTest.class);
+ addTestSuite(WorkspaceCopyBetweenWorkspacesReferenceableTest.class);
+ addTestSuite(WorkspaceCopyBetweenWorkspacesSameNameSibsTest.class);
+ addTestSuite(WorkspaceCopyBetweenWorkspacesTest.class);
+ addTestSuite(WorkspaceCopyBetweenWorkspacesVersionableTest.class);
+ addTestSuite(WorkspaceCopyReferenceableTest.class);
+ addTestSuite(WorkspaceCopySameNameSibsTest.class);
+ addTestSuite(WorkspaceCopyTest.class);
+ addTestSuite(WorkspaceCopyVersionableTest.class);
+ addTestSuite(WorkspaceMoveReferenceableTest.class);
+ addTestSuite(WorkspaceMoveSameNameSibsTest.class);
+ addTestSuite(WorkspaceMoveTest.class);
+ addTestSuite(WorkspaceMoveVersionableTest.class);
+
+ addTestSuite(RepositoryLoginTest.class);
+ addTestSuite(ImpersonateTest.class);
+ addTestSuite(CheckPermissionTest.class);
+
+ // addTestSuite(DocumentViewImportTest.class);
+ addTestSuite(SerializationTest.class);
+
+ addTestSuite(ValueFactoryTest.class);
+ }
+ }
+
}
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java 2009-10-29 21:25:06 UTC
(rev 1315)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/DnaLexicon.java 2009-10-30 21:34:28 UTC
(rev 1316)
@@ -37,7 +37,7 @@
public static final Name IS_HELD_BY_SESSION = new BasicName(Namespace.URI,
"isHeldBySession");
public static final Name IS_SESSION_SCOPED = new BasicName(Namespace.URI,
"isSessionScoped");
public static final Name LOCK = new BasicName(Namespace.URI, "lock");
- public static final Name LOCKED_NODE = new BasicName(Namespace.URI,
"lockedNode");
+ public static final Name LOCKED_UUID = new BasicName(Namespace.URI,
"lockedUuid");
public static final Name LOCKS = new BasicName(Namespace.URI, "locks");
public static final Name NAMESPACE = new BasicName(Namespace.URI,
"namespace");
public static final Name NODE_TYPES = new BasicName(Namespace.URI,
"nodeTypes");
Modified: trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/WorkspaceLockManager.java
===================================================================
--- trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/WorkspaceLockManager.java 2009-10-29
21:25:06 UTC (rev 1315)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/WorkspaceLockManager.java 2009-10-30
21:34:28 UTC (rev 1316)
@@ -94,9 +94,8 @@
batch.create(pathFactory.create(locksPath,
pathFactory.createSegment(lockUuid.toString())),
propFactory.create(JcrLexicon.PRIMARY_TYPE, DnaLexicon.LOCK),
- propFactory.create(JcrLexicon.UUID, nodeUuid.toString()),
propFactory.create(DnaLexicon.WORKSPACE, workspaceName),
- propFactory.create(DnaLexicon.LOCKED_NODE, nodeUuid.toString()),
+ propFactory.create(DnaLexicon.LOCKED_UUID, nodeUuid.toString()),
propFactory.create(DnaLexicon.IS_SESSION_SCOPED, isSessionScoped),
// This gets set after the lock succeeds and the lock token gets
added to the session
propFactory.create(DnaLexicon.IS_HELD_BY_SESSION, false),
Modified: trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/dna_builtins.cnd
===================================================================
--- trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/dna_builtins.cnd 2009-10-29
21:25:06 UTC (rev 1315)
+++ trunk/dna-jcr/src/main/resources/org/jboss/dna/jcr/dna_builtins.cnd 2009-10-30
21:34:28 UTC (rev 1316)
@@ -44,9 +44,8 @@
+ * (nt:nodeType) = nt:nodeType protected version
[dna:lock] > nt:base
-- dna:lockedNode (string) protected ignore
+- dna:lockedUuid (string) protected ignore
- jcr:lockOwner (string) protected ignore
-- jcr:uuid (string) protected ignore
- dna:sessionScope (boolean) protected ignore
- jcr:isDeep (boolean) protected ignore
- dna:isHeldBySession (boolean) protected ignore
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-10-29
21:25:06 UTC (rev 1315)
+++
trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java 2009-10-30
21:34:28 UTC (rev 1316)
@@ -228,6 +228,16 @@
}
}
+ if (uuid == null) {
+ for (Property property : request.properties()) {
+ if (property.getName().equals(JcrLexicon.UUID)) {
+ uuid = uuidFactory.create(property.getFirstValue());
+ uuidString = stringFactory.create(property.getFirstValue());
+ break;
+ }
+ }
+ }
+
switch (request.conflictBehavior()) {
case DO_NOT_REPLACE:
case UPDATE:
@@ -1154,7 +1164,7 @@
Name desiredName,
Path.Segment desiredSegment,
Map<String, String> oldUuidsToNewUuids,
- Map<String, ChildEntity> addedLocations,
+ Map<Location, ChildEntity> addedLocations,
Map<String, Location> deletedLocations ) {
assert fromWorkspace != null;
assert intoWorkspace != null;
@@ -1186,9 +1196,12 @@
case REPLACE_EXISTING_NODE:
try {
if (desiredSegment != null) {
- existingLocation = getActualLocation(intoWorkspace,
-
Location.create(pathFactory.create(actualNewParent.location.getPath(),
-
desiredSegment)));
+ Location nLocation =
Location.create(pathFactory.create(actualNewParent.location.getPath(),
+
desiredSegment));
+ existingLocation = getActualLocation(intoWorkspace, nLocation);
+ nLocation = Location.create(nLocation.getPath(),
UUID.fromString(existingLocation.uuid));
+ assert nLocation.getUuid() != null;
+ deletedLocations.putAll(computeDeletedLocations(intoWorkspace,
nLocation, true));
newUuid =
existingLocation.childEntity.getId().getChildUuidString();
} else {
@@ -1225,11 +1238,12 @@
} else {
// Now add the new copy of the original ...
boolean allowSnS = original.getAllowsSameNameChildren();
+ if (desiredName == null) desiredName = desiredSegment.getName();
newLocation = addNewChild(intoWorkspace.getId(), actualNewParent, newUuid,
desiredName, allowSnS);
}
assert newLocation != null;
- addedLocations.put(newLocation.uuid, newLocation.childEntity);
+ addedLocations.put(newLocation.location, newLocation.childEntity);
return newLocation;
}
@@ -1278,7 +1292,7 @@
// 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<Location, ChildEntity> addedLocations = new
HashMap<Location, 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 ...
@@ -1475,7 +1489,7 @@
// 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<Location, ChildEntity> addedLocations = new
HashMap<Location, 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 ...
@@ -1618,17 +1632,18 @@
* 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());
+ Map<String, Location> netDeletedLocations = new
HashMap<String, Location>(deletedLocations);
+ netDeletedLocations.values().removeAll(addedLocations.keySet());
- if (deletedLocations.size() > 0) {
+ if (netDeletedLocations.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(),
+
netDeletedLocations.keySet(),
entities);
for (Iterator<ReferenceEntity> iter =
invalidReferences.iterator(); iter.hasNext();) {
ReferenceEntity invalidRef = iter.next();
- if
(deletedLocations.keySet().contains(invalidRef.getId().getFromUuidString())) {
+ if
(netDeletedLocations.keySet().contains(invalidRef.getId().getFromUuidString())) {
iter.remove();
}
}
@@ -1657,14 +1672,21 @@
/*
* This list of values that were deleted is expected to be fairly
small
*/
- for (Location location : deletedLocations.values()) {
+ for (Location location : netDeletedLocations.values()) {
ActualLocation node = getActualLocation(intoWorkspace,
location);
- entities.remove(node.childEntity);
+ ChildEntity entity = node.childEntity;
+
+ if (entity != null) {
+ 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());
+ cache.removeBranch(intoWorkspaceId,
netDeletedLocations.values());
+ }
+
+ if (!deletedLocations.isEmpty()) {
removedLocations = Collections.unmodifiableSet(new
HashSet<Location>(deletedLocations.values()));
}
LargeValueEntity.deleteUnused(entities);
@@ -2077,6 +2099,11 @@
Location fromLocation = request.from();
ActualLocation actualLocation = getActualLocation(workspace, fromLocation);
+ if (actualLocation.childEntity == null) {
+ actualLocation = new ActualLocation(actualLocation.location,
actualLocation.uuid, findNode(workspaceId,
+
actualLocation.uuid));
+ }
+
actualOldLocation = actualLocation.location;
Path oldPath = actualOldLocation.getPath();