DNA SVN: r1306 - in trunk: extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic and 1 other directory.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-10-22 20:54:08 -0400 (Thu, 22 Oct 2009)
New Revision: 1306
Modified:
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java
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
Committed patch that pushes the desiredSegment down into the copyNode call (if the desiredSegment is specified). Previously, copyNode was silently converting the desiredSegment field into a desiredName.
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-10-22 10:27:12 UTC (rev 1305)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/JcrTckTest.java 2009-10-23 00:54:08 UTC (rev 1306)
@@ -37,6 +37,7 @@
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;
@@ -198,7 +199,7 @@
// addTestSuite(ReferencesTest.class);
addTestSuite(SessionTest.class);
// addTestSuite(SessionUUIDTest.class);
- // DNA-518 addTestSuite(NodeTest.class);
+ addTestSuite(NodeTest.class);
// addTestSuite(NodeUUIDTest.class);
addTestSuite(NodeOrderableChildNodesTest.class);
addTestSuite(PropertyTest.class);
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-22 10:27:12 UTC (rev 1305)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/model/basic/BasicRequestProcessor.java 2009-10-23 00:54:08 UTC (rev 1306)
@@ -1152,13 +1152,14 @@
ActualLocation actualNewParent,
UuidConflictBehavior uuidConflictBehavior,
Name desiredName,
+ Path.Segment desiredSegment,
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 (desiredName != null ? desiredSegment == null : desiredSegment != null) : "Either desiredName or desiredSegment must not be 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
@@ -1184,10 +1185,17 @@
break;
case REPLACE_EXISTING_NODE:
try {
- existingLocation = getActualLocation(intoWorkspace, Location.create(oldUuid));
- deletedLocations.putAll(computeDeletedLocations(intoWorkspace, existingLocation.location, true));
+ if (desiredSegment != null) {
+ existingLocation = getActualLocation(intoWorkspace,
+ Location.create(pathFactory.create(actualNewParent.location.getPath(),
+ desiredSegment)));
+ newUuid = existingLocation.childEntity.getId().getChildUuidString();
+
+ } else {
+ existingLocation = getActualLocation(intoWorkspace, Location.create(oldUuid));
+ deletedLocations.putAll(computeDeletedLocations(intoWorkspace, existingLocation.location, true));
+ }
} catch (PathNotFoundException pnfe) {
-
}
break;
default:
@@ -1196,6 +1204,7 @@
oldUuidsToNewUuids.put(original.getId().getChildUuidString(), newUuid);
if (existingLocation != null && existingLocation.childEntity.getParentUuidString().equals(actualNewParent.uuid)) {
+ if (desiredName == null) desiredName = desiredSegment.getName();
NamespaceEntity namespace = NamespaceEntity.findByUri(entities, desiredName.getNamespaceUri());
ChildEntity existingChild = existingLocation.childEntity;
@@ -1285,6 +1294,7 @@
actualNewParent,
UuidConflictBehavior.ALWAYS_CREATE_NEW_UUID,
desiredName,
+ null,
originalToNewUuid,
addedLocations,
deletedLocations).location;
@@ -1306,6 +1316,7 @@
actualNewParent,
UuidConflictBehavior.ALWAYS_CREATE_NEW_UUID,
desiredName,
+ null,
originalToNewUuid,
addedLocations,
deletedLocations);
@@ -1472,7 +1483,6 @@
ChildEntity original = originalIter.next();
Name desiredName = request.desiredName();
- if (desiredName == null) desiredName = fromPath.getLastSegment().getName();
actualToLocation = this.copyNode(entities,
fromWorkspace,
intoWorkspace,
@@ -1480,6 +1490,7 @@
actualNewParent,
conflictBehavior,
desiredName,
+ desiredName != null ? null : fromPath.getLastSegment(),
originalToNewUuid,
addedLocations,
deletedLocations).location;
@@ -1501,6 +1512,7 @@
actualNewParent,
conflictBehavior,
desiredName,
+ null,
originalToNewUuid,
addedLocations,
deletedLocations);
@@ -2087,8 +2099,8 @@
} else {
ActualLocation actualBeforeLocation = getActualLocation(workspace, beforeLocation);
- ActualLocation actualIntoLocation = getActualLocation(workspace, Location.create(beforeLocation.getPath()
- .getParent()));
+ ActualLocation actualIntoLocation = getActualLocation(workspace,
+ Location.create(beforeLocation.getPath().getParent()));
actualNewLocation = moveNodeBefore(workspace, actualLocation, actualIntoLocation, actualBeforeLocation);
}
16 years, 2 months
DNA SVN: r1305 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory and 3 other directories.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-10-22 06:27:12 -0400 (Thu, 22 Oct 2009)
New Revision: 1305
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.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/query/optimize/RewriteIdentityJoins.java
trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java
Log:
Cleaned up some things that work in Java6 but are breaking the build in Java5
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-10-21 22:12:10 UTC (rev 1304)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-10-22 10:27:12 UTC (rev 1305)
@@ -4743,12 +4743,10 @@
public LockTimeout<T> andItsDescendants() {
return new LockTimeout<T>() {
- @Override
public T withDefaultTimeout() {
return submit(target, org.jboss.dna.graph.request.LockBranchRequest.LockScope.SELF_AND_DESCENDANTS, 0);
}
- @Override
public T withTimeoutOf( long milliseconds ) {
return submit(target,
org.jboss.dna.graph.request.LockBranchRequest.LockScope.SELF_AND_DESCENDANTS,
@@ -4761,12 +4759,10 @@
public LockTimeout<T> only() {
return new LockTimeout<T>() {
- @Override
public T withDefaultTimeout() {
return submit(target, org.jboss.dna.graph.request.LockBranchRequest.LockScope.SELF_ONLY, 0);
}
- @Override
public T withTimeoutOf( long milliseconds ) {
return submit(target, org.jboss.dna.graph.request.LockBranchRequest.LockScope.SELF_ONLY, milliseconds);
}
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-10-21 22:12:10 UTC (rev 1304)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java 2009-10-22 10:27:12 UTC (rev 1305)
@@ -126,14 +126,12 @@
return super.copyNode(context, original, newWorkspace, newParent, desiredName, recursive, oldToNewUuids);
}
- @Override
public void lockNode( MapNode node,
LockScope lockScope,
long lockTimeoutInMillis ) throws LockFailedException {
// Locking is not supported by this connector
}
- @Override
public void unlockNode( MapNode node ) {
// Locking is not supported by this connector
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RewriteIdentityJoins.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RewriteIdentityJoins.java 2009-10-21 22:12:10 UTC (rev 1304)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RewriteIdentityJoins.java 2009-10-22 10:27:12 UTC (rev 1305)
@@ -157,7 +157,7 @@
ruleStack.addFirst(this);
// After this rule is done as is no longer needed, we need to try to push SELECTs and PROJECTs again ...
- if (!(ruleStack.peekFirst() instanceof PushSelectCriteria)) {
+ if (!(ruleStack.peek() instanceof PushSelectCriteria)) {
// We haven't already added these, so add them now ...
ruleStack.addFirst(PushProjects.INSTANCE);
if (context.getHints().hasCriteria) {
Modified: trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java 2009-10-21 22:12:10 UTC (rev 1304)
+++ trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java 2009-10-22 10:27:12 UTC (rev 1305)
@@ -83,14 +83,12 @@
return workspaceCache.get(nodeUuid);
}
- @Override
public void lockNode( MapNode node,
LockScope lockScope,
long lockTimeoutInMillis ) throws LockFailedException {
// Locking is not supported by this connector
}
- @Override
public void unlockNode( MapNode node ) {
// Locking is not supported by this connector
}
Modified: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java 2009-10-21 22:12:10 UTC (rev 1304)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java 2009-10-22 10:27:12 UTC (rev 1305)
@@ -84,14 +84,12 @@
return workspaceNode.get(nodeUuid);
}
- @Override
public void lockNode( MapNode node,
LockScope lockScope,
long lockTimeoutInMillis ) throws LockFailedException {
// Locking is not supported by this connector
}
- @Override
public void unlockNode( MapNode node ) {
// Locking is not supported by this connector
}
16 years, 2 months
DNA SVN: r1304 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/connector and 12 other directories.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-10-21 18:12:10 -0400 (Wed, 21 Oct 2009)
New Revision: 1304
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/LockFailedException.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/LockBranchRequest.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UnlockBranchRequest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/WorkspaceLockManagerTest.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/RepositorySourceCapabilities.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/map/MapRepository.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapWorkspace.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/LoggingRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/RequestProcessor.java
trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties
trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/MockRepositoryRequestProcessor.java
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/WorkspaceLockManager.java
trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java
trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java
Log:
DNA-457 Add JSR-170 Locking Optional Feature
Committed patch (DNA-457_repo_locks.patch) that adds comments to address the previous feedback and provides a graph-layer API for locking nodes in repositories that provide their own locking mechanism (e.g., SVN). The patch also modifies the JCR locking code to propagate JCR locks to the graph layer.
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-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -406,6 +406,165 @@
}
/**
+ * Request to lock the specified node. This request is submitted to the repository immediately.
+ *
+ * @param at the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<Conjunction<Graph>>> lock( Node at ) {
+ return lock(at.getLocation());
+ }
+
+ /**
+ * Request to lock the node at the given path. This request is submitted to the repository immediately.
+ *
+ * @param atPath the path of the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<Conjunction<Graph>>> lock( String atPath ) {
+ return lock(Location.create(createPath(atPath)));
+ }
+
+ /**
+ * Request to lock the node at the given path. This request is submitted to the repository immediately.
+ *
+ * @param at the path of the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<Conjunction<Graph>>> lock( Path at ) {
+ return lock(Location.create(at));
+ }
+
+ /**
+ * Request to lock the node with the given UUID. This request is submitted to the repository immediately.
+ *
+ * @param at the UUID of the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<Conjunction<Graph>>> lock( UUID at ) {
+ return lock(Location.create(at));
+ }
+
+ /**
+ * Request to lock the node with the given unique identification property. This request is submitted to the repository
+ * immediately.
+ *
+ * @param idProperty the unique identifying property of the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<Conjunction<Graph>>> lock( Property idProperty ) {
+ return lock(Location.create(idProperty));
+ }
+
+ /**
+ * Request to lock the node with the given identification properties. The identification properties should uniquely identify a
+ * single node. This request is submitted to the repository immediately.
+ *
+ * @param firstIdProperty the first identification property of the node that is to be copied
+ * @param additionalIdProperties the remaining identification properties of the node that is to be copied
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<Conjunction<Graph>>> lock( Property firstIdProperty,
+ Property... additionalIdProperties ) {
+ return lock(Location.create(firstIdProperty, additionalIdProperties));
+ }
+
+ /**
+ * Request to lock the node at the given location. This request is submitted to the repository immediately.
+ *
+ * @param at the location of the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<Conjunction<Graph>>> lock( Location at ) {
+ return new LockAction<Conjunction<Graph>>(this.nextGraph, at) {
+ @Override
+ protected Conjunction<Graph> submit( Location target,
+ org.jboss.dna.graph.request.LockBranchRequest.LockScope lockScope,
+ long lockTimeoutInMillis ) {
+ String workspaceName = getCurrentWorkspaceName();
+ requests.lockBranch(workspaceName, target, lockScope, lockTimeoutInMillis);
+ return and();
+ }
+ };
+ }
+
+ /**
+ * Request to unlock the specified node. This request is submitted to the repository immediately.
+ *
+ * @param at the node that is to be unlocked
+ * @return an object that may be used to start another request
+ */
+ public Conjunction<Graph> unlock( Node at ) {
+ return unlock(at.getLocation());
+ }
+
+ /**
+ * Request to unlock the node at the given path. This request is submitted to the repository immediately.
+ *
+ * @param atPath the path of the node that is to be unlocked
+ * @return an object that may be used to start another request
+ */
+ public Conjunction<Graph> unlock( String atPath ) {
+ return unlock(Location.create(createPath(atPath)));
+ }
+
+ /**
+ * Request to unlock the node at the given path. This request is submitted to the repository immediately.
+ *
+ * @param at the path of the node that is to be unlocked
+ * @return an object that may be used to start another request
+ */
+ public Conjunction<Graph> unlock( Path at ) {
+ return unlock(Location.create(at));
+ }
+
+ /**
+ * Request to unlock the node with the given UUID. This request is submitted to the repository immediately.
+ *
+ * @param at the UUID of the node that is to be unlocked
+ * @return an object that may be used to start another request
+ */
+ public Conjunction<Graph> unlock( UUID at ) {
+ return unlock(Location.create(at));
+ }
+
+ /**
+ * Request to unlock the node with the given unique identification property. This request is submitted to the repository
+ * immediately.
+ *
+ * @param idProperty the unique identifying property of the node that is to be unlocked
+ * @return an object that may be used to start another request
+ */
+ public Conjunction<Graph> unlock( Property idProperty ) {
+ return unlock(Location.create(idProperty));
+ }
+
+ /**
+ * Request to unlock the node with the given identification properties. The identification properties should uniquely identify
+ * a single node. This request is submitted to the repository immediately.
+ *
+ * @param firstIdProperty the first identification property of the node that is to be copied
+ * @param additionalIdProperties the remaining identification properties of the node that is to be copied
+ * @return an object that may be used to start another request
+ */
+ public Conjunction<Graph> unlock( Property firstIdProperty,
+ Property... additionalIdProperties ) {
+ return unlock(Location.create(firstIdProperty, additionalIdProperties));
+ }
+
+ /**
+ * Request to unlock the node at the given location. This request is submitted to the repository immediately.
+ *
+ * @param at the location of the node that is to be unlocked
+ * @return an object that may be used to start another request
+ */
+ public Conjunction<Graph> unlock( Location at ) {
+ String workspaceName = getCurrentWorkspaceName();
+ requests.unlockBranch(workspaceName, at);
+ return this.nextGraph;
+ }
+
+ /**
* Begin the request to move the specified node into a parent node at a different location, which is specified via the
* <code>into(...)</code> method on the returned {@link Move} object.
* <p>
@@ -1847,15 +2006,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 ) {
@@ -2450,6 +2607,164 @@
}
/**
+ * Request to lock the specified node. This request is submitted to the repository immediately.
+ *
+ * @param at the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<BatchConjunction>> lock( Node at ) {
+ return lock(at.getLocation());
+ }
+
+ /**
+ * Request to lock the node at the given path. This request is submitted to the repository immediately.
+ *
+ * @param atPath the path of the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<BatchConjunction>> lock( String atPath ) {
+ return lock(Location.create(createPath(atPath)));
+ }
+
+ /**
+ * Request to lock the node at the given path. This request is submitted to the repository immediately.
+ *
+ * @param at the path of the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<BatchConjunction>> lock( Path at ) {
+ return lock(Location.create(at));
+ }
+
+ /**
+ * Request to lock the node with the given UUID. This request is submitted to the repository immediately.
+ *
+ * @param at the UUID of the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<BatchConjunction>> lock( UUID at ) {
+ return lock(Location.create(at));
+ }
+
+ /**
+ * Request to lock the node with the given unique identification property. This request is submitted to the repository
+ * immediately.
+ *
+ * @param idProperty the unique identifying property of the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<BatchConjunction>> lock( Property idProperty ) {
+ return lock(Location.create(idProperty));
+ }
+
+ /**
+ * Request to lock the node with the given identification properties. The identification properties should uniquely
+ * identify a single node. This request is submitted to the repository immediately.
+ *
+ * @param firstIdProperty the first identification property of the node that is to be copied
+ * @param additionalIdProperties the remaining identification properties of the node that is to be copied
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<BatchConjunction>> lock( Property firstIdProperty,
+ Property... additionalIdProperties ) {
+ return lock(Location.create(firstIdProperty, additionalIdProperties));
+ }
+
+ /**
+ * Request to lock the node at the given location. This request is submitted to the repository immediately.
+ *
+ * @param at the location of the node that is to be locked
+ * @return an object that allows the scope of the lock to be defined
+ */
+ public LockScope<LockTimeout<BatchConjunction>> lock( Location at ) {
+ return new LockAction<BatchConjunction>(this.nextRequests, at) {
+ @Override
+ protected BatchConjunction submit( Location target,
+ org.jboss.dna.graph.request.LockBranchRequest.LockScope lockScope,
+ long lockTimeoutInMillis ) {
+ String workspaceName = getCurrentWorkspaceName();
+ requests.lockBranch(workspaceName, target, lockScope, lockTimeoutInMillis);
+ return and();
+ }
+ };
+ }
+
+ /**
+ * Request to unlock the specified node. This request is submitted to the repository immediately.
+ *
+ * @param at the node that is to be unlocked
+ * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
+ */
+ public BatchConjunction unlock( Node at ) {
+ return unlock(at.getLocation());
+ }
+
+ /**
+ * Request to unlock the node at the given path. This request is submitted to the repository immediately.
+ *
+ * @param atPath the path of the node that is to be unlocked
+ * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
+ */
+ public BatchConjunction unlock( String atPath ) {
+ return unlock(Location.create(createPath(atPath)));
+ }
+
+ /**
+ * Request to unlock the node at the given path. This request is submitted to the repository immediately.
+ *
+ * @param at the path of the node that is to be unlocked
+ * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
+ */
+ public BatchConjunction unlock( Path at ) {
+ return unlock(Location.create(at));
+ }
+
+ /**
+ * Request to unlock the node with the given UUID. This request is submitted to the repository immediately.
+ *
+ * @param at the UUID of the node that is to be unlocked
+ * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
+ */
+ public BatchConjunction unlock( UUID at ) {
+ return unlock(Location.create(at));
+ }
+
+ /**
+ * Request to unlock the node with the given unique identification property. This request is submitted to the repository
+ * immediately.
+ *
+ * @param idProperty the unique identifying property of the node that is to be unlocked
+ * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
+ */
+ public BatchConjunction unlock( Property idProperty ) {
+ return unlock(Location.create(idProperty));
+ }
+
+ /**
+ * Request to unlock the node with the given identification properties. The identification properties should uniquely
+ * identify a single node. This request is submitted to the repository immediately.
+ *
+ * @param firstIdProperty the first identification property of the node that is to be copied
+ * @param additionalIdProperties the remaining identification properties of the node that is to be copied
+ * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
+ */
+ public BatchConjunction unlock( Property firstIdProperty,
+ Property... additionalIdProperties ) {
+ return unlock(Location.create(firstIdProperty, additionalIdProperties));
+ }
+
+ /**
+ * Request to unlock the node at the given location. This request is submitted to the repository immediately.
+ *
+ * @param at the location of the node that is to be unlocked
+ * @return the interface that can either execute the batched requests or continue to add additional requests to the batch
+ */
+ public BatchConjunction unlock( Location at ) {
+ requests.unlockBranch(workspaceName, at);
+ return this.nextRequests;
+ }
+
+ /**
* Begin the request to clone the specified node into a parent node at a different location, which is specified via the
* <code>into(...)</code> method on the returned {@link Clone} object.
* <p>
@@ -4390,6 +4705,78 @@
}
/**
+ * Interface for specifying whether a lock should be deep in scope
+ *
+ * @param <Next> The interface that is to be returned when this create request is completed
+ */
+ public interface LockScope<Next> {
+ Next andItsDescendants();
+
+ Next only();
+ }
+
+ /**
+ * Interface for specifying whether the maximum length of the lock
+ *
+ * @param <Next> The interface that is to be returned when this create request is completed
+ */
+ public interface LockTimeout<Next> {
+ Next withDefaultTimeout();
+
+ Next withTimeoutOf( long milliseconds );
+ }
+
+ @NotThreadSafe
+ protected abstract class LockAction<T> extends AbstractAction<T> implements LockScope<LockTimeout<T>> {
+ private final Location target;
+
+ /*package*/LockAction( T afterConjunction,
+ Location target ) {
+ super(afterConjunction);
+ this.target = target;
+ }
+
+ protected abstract T submit( Location lock,
+ org.jboss.dna.graph.request.LockBranchRequest.LockScope lockScope,
+ long lockTimeoutInMillis );
+
+ public LockTimeout<T> andItsDescendants() {
+ return new LockTimeout<T>() {
+
+ @Override
+ public T withDefaultTimeout() {
+ return submit(target, org.jboss.dna.graph.request.LockBranchRequest.LockScope.SELF_AND_DESCENDANTS, 0);
+ }
+
+ @Override
+ public T withTimeoutOf( long milliseconds ) {
+ return submit(target,
+ org.jboss.dna.graph.request.LockBranchRequest.LockScope.SELF_AND_DESCENDANTS,
+ milliseconds);
+ }
+
+ };
+ }
+
+ public LockTimeout<T> only() {
+ return new LockTimeout<T>() {
+
+ @Override
+ public T withDefaultTimeout() {
+ return submit(target, org.jboss.dna.graph.request.LockBranchRequest.LockScope.SELF_ONLY, 0);
+ }
+
+ @Override
+ public T withTimeoutOf( long milliseconds ) {
+ return submit(target, org.jboss.dna.graph.request.LockBranchRequest.LockScope.SELF_ONLY, milliseconds);
+ }
+
+ };
+ }
+
+ }
+
+ /**
* 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
@@ -6041,10 +6428,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);
}
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-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -89,6 +89,7 @@
public static I18n errorImportingContent;
public static I18n unableToFindRepositorySourceWithName;
public static I18n nodeAlreadyExistsWithUuid;
+ public static I18n couldNotAcquireLock;
/* In-Memory Connector */
public static I18n inMemoryNodeDoesNotExist;
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/LockFailedException.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/LockFailedException.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/LockFailedException.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -0,0 +1,46 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.connector;
+
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.Location;
+
+/**
+ * Exception that indicates that a lock request failed at the repository level. This may be due to a conflict with an existing
+ * lock, an internal timeout that occurred while attempting to lock the target, a lack of permissions, or any other reason.
+ */
+@Immutable
+public class LockFailedException extends RepositorySourceException {
+
+ private static final long serialVersionUID = 1L;
+
+ public LockFailedException( String repositorySourceName,
+ Location target,
+ String workspaceName,
+ Throwable cause ) {
+ super(repositorySourceName, GraphI18n.couldNotAcquireLock.text(target, workspaceName), cause);
+ }
+
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/LockFailedException.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/RepositorySourceCapabilities.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/RepositorySourceCapabilities.java 2009-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/RepositorySourceCapabilities.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -59,24 +59,30 @@
*/
public static final boolean DEFAULT_SUPPORT_REFERENCES = true;
- private boolean sameNameSiblings;
- private boolean updates;
- private boolean events;
- private boolean creatingWorkspaces;
- private boolean references;
+ /**
+ * The default support for creating locks is {@value} .
+ */
+ public static final boolean DEFAULT_SUPPORT_LOCKS = false;
+ private final boolean sameNameSiblings;
+ private final boolean updates;
+ private final boolean events;
+ private final boolean creatingWorkspaces;
+ private final boolean references;
+ private final boolean locks;
+
/**
* Create a capabilities object using the defaults, .
*/
public RepositorySourceCapabilities() {
this(DEFAULT_SUPPORT_SAME_NAME_SIBLINGS, DEFAULT_SUPPORT_UPDATES, DEFAULT_SUPPORT_EVENTS,
- DEFAULT_SUPPORT_CREATING_WORKSPACES, DEFAULT_SUPPORT_REFERENCES);
+ DEFAULT_SUPPORT_CREATING_WORKSPACES, DEFAULT_SUPPORT_REFERENCES, DEFAULT_SUPPORT_LOCKS);
}
public RepositorySourceCapabilities( boolean supportsSameNameSiblings,
boolean supportsUpdates ) {
this(supportsSameNameSiblings, supportsUpdates, DEFAULT_SUPPORT_EVENTS, DEFAULT_SUPPORT_CREATING_WORKSPACES,
- DEFAULT_SUPPORT_REFERENCES);
+ DEFAULT_SUPPORT_REFERENCES, DEFAULT_SUPPORT_LOCKS);
}
public RepositorySourceCapabilities( boolean supportsSameNameSiblings,
@@ -84,11 +90,24 @@
boolean supportsEvents,
boolean supportsCreatingWorkspaces,
boolean supportsReferences ) {
+ this(supportsSameNameSiblings, supportsUpdates, supportsEvents, supportsCreatingWorkspaces, supportsReferences,
+ DEFAULT_SUPPORT_LOCKS);
+
+ }
+
+ public RepositorySourceCapabilities( boolean supportsSameNameSiblings,
+ boolean supportsUpdates,
+ boolean supportsEvents,
+ boolean supportsCreatingWorkspaces,
+ boolean supportsReferences,
+ boolean supportsLocks ) {
+
this.sameNameSiblings = supportsSameNameSiblings;
this.updates = supportsUpdates;
this.events = supportsEvents;
this.creatingWorkspaces = supportsCreatingWorkspaces;
this.references = supportsReferences;
+ this.locks = supportsLocks;
}
/**
@@ -121,6 +140,19 @@
}
/**
+ * Return whether the source supports locking nodes.
+ * <p>
+ * Sources that support locking nodes must be able to explicitly lock and unlock nodes in a manner that is persistent and
+ * stable across repository connections. Sources that cannot provide this capability should return false from this method.
+ * </p>
+ *
+ * @return true if locks are supported, or false otherwise
+ */
+ public boolean supportsLocks() {
+ return locks;
+ }
+
+ /**
* Return whether the source supports publishing change events.
*
* @return true if events are supported, or false if the source is not capable of generating events
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-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/inmemory/InMemoryRepository.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -29,11 +29,13 @@
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.LockFailedException;
import org.jboss.dna.graph.connector.map.AbstractMapWorkspace;
import org.jboss.dna.graph.connector.map.MapNode;
import org.jboss.dna.graph.connector.map.MapRepository;
import org.jboss.dna.graph.connector.map.MapWorkspace;
import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.request.LockBranchRequest.LockScope;
/**
* A specialized {@link MapRepository} that represents an in-memory repository.
@@ -124,6 +126,18 @@
return super.copyNode(context, original, newWorkspace, newParent, desiredName, recursive, oldToNewUuids);
}
+ @Override
+ public void lockNode( MapNode node,
+ LockScope lockScope,
+ long lockTimeoutInMillis ) throws LockFailedException {
+ // Locking is not supported by this connector
+ }
+
+ @Override
+ public void unlockNode( MapNode node ) {
+ // Locking is not supported by this connector
+ }
+
/**
* Method added to support testing
*
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepository.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepository.java 2009-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRepository.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -266,5 +266,4 @@
public boolean destroyWorkspace( String name ) {
return workspaces.remove(name) != null;
}
-
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java 2009-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapRequestProcessor.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -54,10 +54,12 @@
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
import org.jboss.dna.graph.request.GetWorkspacesRequest;
import org.jboss.dna.graph.request.InvalidWorkspaceException;
+import org.jboss.dna.graph.request.LockBranchRequest;
import org.jboss.dna.graph.request.MoveBranchRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
import org.jboss.dna.graph.request.Request;
+import org.jboss.dna.graph.request.UnlockBranchRequest;
import org.jboss.dna.graph.request.UpdatePropertiesRequest;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
import org.jboss.dna.graph.request.processor.RequestProcessor;
@@ -103,6 +105,32 @@
}
@Override
+ public void process( LockBranchRequest request ) {
+ MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ MapNode node = getTargetNode(workspace, request, request.at());
+ if (node == null) return;
+
+ workspace.lockNode(node, request.lockScope(), request.lockTimeoutInMillis());
+
+ Location actualLocation = getActualLocation(request.at(), node);
+ request.setActualLocation(actualLocation);
+ recordChange(request);
+ }
+
+ @Override
+ public void process( UnlockBranchRequest request ) {
+ MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
+ MapNode node = getTargetNode(workspace, request, request.at());
+ if (node == null) return;
+
+ workspace.unlockNode(node);
+
+ Location actualLocation = getActualLocation(request.at(), node);
+ request.setActualLocation(actualLocation);
+ recordChange(request);
+ }
+
+ @Override
public void process( ReadAllPropertiesRequest request ) {
MapWorkspace workspace = getWorkspace(request, request.inWorkspace());
MapNode node = getTargetNode(workspace, request, request.at());
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapWorkspace.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapWorkspace.java 2009-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/map/MapWorkspace.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -27,10 +27,12 @@
import java.util.UUID;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.LockFailedException;
import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
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.request.LockBranchRequest.LockScope;
/**
* The {@code MapWorkspace} defines the required methods for workspaces in a {@link MapRepository map repository}. By default, a
@@ -180,6 +182,27 @@
Set<Location> removedExistingNodes ) throws UuidAlreadyExistsException;
/**
+ * Attempts to lock the given node with the given timeout. If the lock attempt fails, a {@link LockFailedException} will be
+ * thrown.
+ *
+ * @param node the node to be locked; may not be null
+ * @param lockScope the scope of the lock (i.e., whether descendants of {@code node} should be included in the lock
+ * @param lockTimeoutInMillis the maximum lifetime of the lock in milliseconds; zero (0) indicates that the connector default
+ * should be used
+ * @throws LockFailedException if the implementing connector supports locking but the lock could not be acquired.
+ */
+ void lockNode( MapNode node,
+ LockScope lockScope,
+ long lockTimeoutInMillis ) throws LockFailedException;
+
+ /**
+ * Attempts to unlock the given node.
+ *
+ * @param node the node to be unlocked; may not be null
+ */
+ void unlockNode( MapNode node );
+
+ /**
* Find the lowest existing node along the path.
*
* @param path the path to the node; may not be null
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/LockBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/LockBranchRequest.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/LockBranchRequest.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -0,0 +1,234 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.request;
+
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.RepositorySourceCapabilities;
+import org.jboss.dna.graph.property.Path;
+
+/**
+ * Instruction to lock an existing node or branch. Connectors that do not support locking (as defined in
+ * {@link RepositorySourceCapabilities#supportsLocks()}) must ignore this request.
+ */
+public class LockBranchRequest extends ChangeRequest {
+
+ private static final long serialVersionUID = 1L;
+
+ public enum LockScope {
+ SELF_ONLY,
+ SELF_AND_DESCENDANTS;
+ }
+
+ private final Location at;
+ private final String workspaceName;
+ private final LockScope isDeep;
+ private final long lockTimeoutInMillis;
+ private Location actualLocation;
+
+ /**
+ * Create a request to lock the node or branch at the supplied location.
+ *
+ * @param at the location of the node to be read
+ * @param workspaceName the name of the workspace containing the node
+ * @param isDeep whether the lock should be deep (i.e., should include all of the node's descendants)
+ * @param lockTimeoutInMillis the number of milliseconds that the lock should last before the lock times out; zero (0)
+ * indicates that the connector default should be used
+ * @throws IllegalArgumentException if the location or workspace name is null
+ */
+ public LockBranchRequest( Location at,
+ String workspaceName,
+ LockScope isDeep,
+ long lockTimeoutInMillis ) {
+ CheckArg.isNotNull(at, "at");
+ CheckArg.isNotNull(workspaceName, "workspaceName");
+ this.workspaceName = workspaceName;
+ this.at = at;
+ this.isDeep = isDeep;
+ this.lockTimeoutInMillis = lockTimeoutInMillis;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.Request#isReadOnly()
+ */
+ @Override
+ public boolean isReadOnly() {
+ return false;
+ }
+
+ /**
+ * Get the location defining the node that is to be read.
+ *
+ * @return the location of the node; never null
+ */
+ public Location at() {
+ return at;
+ }
+
+ /**
+ * Get the name of the workspace in which the node exists.
+ *
+ * @return the name of the workspace; never null
+ */
+ public String inWorkspace() {
+ return workspaceName;
+ }
+
+ /**
+ * Get whether the lock should include all of the descendants of the node as well as the node itself
+ *
+ * @return {@link LockScope#SELF_AND_DESCENDANTS} if the lock should include all of the descendants of the node,
+ * {@link LockScope#SELF_ONLY} otherwise
+ */
+ public LockScope lockScope() {
+ return isDeep;
+ }
+
+ /**
+ * Gets the maximum length of the lock in milliseconds
+ *
+ * @return the number of milliseconds that the lock should last before the lock times out; zero (0) indicates that the
+ * connector default should be used
+ */
+ public long lockTimeoutInMillis() {
+ return lockTimeoutInMillis;
+ }
+
+ /**
+ * Sets the actual and complete location of the node being locked. This method must be called when processing the request, and
+ * the actual location must have a {@link Location#getPath() path}.
+ *
+ * @param actualLocation the actual location of the node before being locked
+ * @throws IllegalArgumentException if the either location is null or is missing its path, if the old location does not
+ * represent the {@link Location#isSame(Location) same location} as the {@link #at() current location}
+ * @throws IllegalStateException if the request is frozen
+ */
+ public void setActualLocation( Location actualLocation ) {
+ checkNotFrozen();
+ if (!at.isSame(actualLocation)) { // not same if actual is null
+ throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actualLocation, at));
+ }
+ assert actualLocation != null;
+ if (!actualLocation.hasPath()) {
+ throw new IllegalArgumentException(GraphI18n.actualOldLocationMustHavePath.text(actualLocation));
+ }
+ this.actualLocation = actualLocation;
+ }
+
+ /**
+ * Get the actual location of the node that was locked.
+ *
+ * @return the actual location of the node being locked, or null if the actual location was not set
+ */
+ public Location getActualLocation() {
+ return actualLocation;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.ChangeRequest#changes(java.lang.String, org.jboss.dna.graph.property.Path)
+ */
+ @Override
+ public boolean changes( String workspace,
+ Path path ) {
+ return this.workspaceName.equals(workspace) && at.hasPath() && at.getPath().getParent().isAtOrBelow(path);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.ChangeRequest#changedLocation()
+ */
+ @Override
+ public Location changedLocation() {
+ return at;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.ChangeRequest#changedWorkspace()
+ */
+ @Override
+ public String changedWorkspace() {
+ return workspaceName;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.Request#cancel()
+ */
+ @Override
+ public void cancel() {
+ super.cancel();
+ this.actualLocation = null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.compute(at, workspaceName, lockScope(), lockTimeoutInMillis);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (this.getClass().isInstance(obj)) {
+ LockBranchRequest that = (LockBranchRequest)obj;
+ if (this.lockTimeoutInMillis() != that.lockTimeoutInMillis()) return false;
+ if (!this.at().equals(that.at())) return false;
+ if (this.lockScope() != that.lockScope()) return false;
+ if (!this.inWorkspace().equals(that.inWorkspace())) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "lock " + (LockScope.SELF_AND_DESCENDANTS == lockScope() ? "branch rooted" : "node") + " at " + at()
+ + " in the \"" + workspaceName + "\" workspace";
+ }
+
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/LockBranchRequest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
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-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -35,6 +35,7 @@
import org.jboss.dna.graph.property.Property;
import org.jboss.dna.graph.request.CloneWorkspaceRequest.CloneConflictBehavior;
import org.jboss.dna.graph.request.CreateWorkspaceRequest.CreateConflictBehavior;
+import org.jboss.dna.graph.request.LockBranchRequest.LockScope;
/**
* A component that can be used to build requests while allowing different strategies for how requests are handled. Subclasses can
@@ -616,4 +617,38 @@
return request;
}
+ /**
+ * Create a request to lock a branch or node
+ *
+ * @param workspaceName the name of the workspace containing the node; may not be null
+ * @param target the location of the top node in the existing branch that is to be locked
+ * @param lockScope the {@link LockBranchRequest#lockScope()} scope of the lock
+ * @param lockTimeoutInMillis the number of milliseconds that the lock should last before the lock times out; zero (0)
+ * indicates that the connector default should be used
+ * @return the request; never null
+ * @throws IllegalArgumentException if any of the parameters are null
+ */
+ public LockBranchRequest lockBranch( String workspaceName,
+ Location target,
+ LockScope lockScope,
+ long lockTimeoutInMillis ) {
+ return process(new LockBranchRequest(target, workspaceName, lockScope, lockTimeoutInMillis));
+ }
+
+ /**
+ * Create a request to unlock a branch or node
+ * <p>
+ * The lock on the node should be removed. If the lock was deep (i.e., locked the entire branch under the node, then all of
+ * the descendants of the node affected by the lock should also be unlocked after this request is processed.
+ * </p>
+ *
+ * @param workspaceName the name of the workspace containing the node; may not be null
+ * @param target the location of the top node in the existing branch that is to be unlocked
+ * @return the request; never null
+ * @throws IllegalArgumentException if any of the parameters are null
+ */
+ public UnlockBranchRequest unlockBranch( String workspaceName,
+ Location target ) {
+ return process(new UnlockBranchRequest(target, workspaceName));
+ }
}
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UnlockBranchRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UnlockBranchRequest.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UnlockBranchRequest.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -0,0 +1,197 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.request;
+
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.RepositorySourceCapabilities;
+import org.jboss.dna.graph.property.Path;
+
+/**
+ * Instruction to unlock an existing node or branch. Connectors that do not support locking (as defined in
+ * {@link RepositorySourceCapabilities#supportsLocks()}) must ignore this request.
+ */
+public class UnlockBranchRequest extends ChangeRequest {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Location at;
+ private final String workspaceName;
+ private Location actualLocation;
+
+ /**
+ * Create a request to unlock the node or branch at the supplied location.
+ *
+ * @param at the location of the node to be unlocked
+ * @param workspaceName the name of the workspace containing the node
+ * @throws IllegalArgumentException if the location or workspace name is null
+ */
+ public UnlockBranchRequest( Location at,
+ String workspaceName ) {
+ CheckArg.isNotNull(at, "at");
+ CheckArg.isNotNull(workspaceName, "workspaceName");
+ this.workspaceName = workspaceName;
+ this.at = at;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.Request#isReadOnly()
+ */
+ @Override
+ public boolean isReadOnly() {
+ return false;
+ }
+
+ /**
+ * Get the location defining the node that is to be read.
+ *
+ * @return the location of the node; never null
+ */
+ public Location at() {
+ return at;
+ }
+
+ /**
+ * Get the name of the workspace in which the node exists.
+ *
+ * @return the name of the workspace; never null
+ */
+ public String inWorkspace() {
+ return workspaceName;
+ }
+
+ /**
+ * Sets the actual and complete location of the node being unlocked. This method must be called when processing the request,
+ * and the actual location must have a {@link Location#getPath() path}.
+ *
+ * @param actualLocation the actual location of the node before being unlocked
+ * @throws IllegalArgumentException if the either location is null or is missing its path, if the old location does not
+ * represent the {@link Location#isSame(Location) same location} as the {@link #at() current location}
+ * @throws IllegalStateException if the request is frozen
+ */
+ public void setActualLocation( Location actualLocation ) {
+ checkNotFrozen();
+ if (!at.isSame(actualLocation)) { // not same if actual is null
+ throw new IllegalArgumentException(GraphI18n.actualLocationIsNotSameAsInputLocation.text(actualLocation, at));
+ }
+ assert actualLocation != null;
+ if (!actualLocation.hasPath()) {
+ throw new IllegalArgumentException(GraphI18n.actualOldLocationMustHavePath.text(actualLocation));
+ }
+ this.actualLocation = actualLocation;
+ }
+
+ /**
+ * Get the actual location of the node that was unlocked.
+ *
+ * @return the actual location of the node being unlocked, or null if the actual location was not set
+ */
+ public Location getActualLocation() {
+ return actualLocation;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.ChangeRequest#changes(java.lang.String, org.jboss.dna.graph.property.Path)
+ */
+ @Override
+ public boolean changes( String workspace,
+ Path path ) {
+ return this.workspaceName.equals(workspace) && at.hasPath() && at.getPath().getParent().isAtOrBelow(path);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.ChangeRequest#changedLocation()
+ */
+ @Override
+ public Location changedLocation() {
+ return at;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.ChangeRequest#changedWorkspace()
+ */
+ @Override
+ public String changedWorkspace() {
+ return workspaceName;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.Request#cancel()
+ */
+ @Override
+ public void cancel() {
+ super.cancel();
+ this.actualLocation = null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return HashCode.compute(at, workspaceName);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals( Object obj ) {
+ if (obj == this) return true;
+ if (this.getClass().isInstance(obj)) {
+ UnlockBranchRequest that = (UnlockBranchRequest)obj;
+ if (!this.at().equals(that.at())) return false;
+ if (!this.inWorkspace().equals(that.inWorkspace())) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "unlock branch at " + at() + " in the \"" + workspaceName + "\" workspace";
+ }
+
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/UnlockBranchRequest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/LoggingRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/LoggingRequestProcessor.java 2009-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/LoggingRequestProcessor.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -36,6 +36,7 @@
import org.jboss.dna.graph.request.DeleteBranchRequest;
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
import org.jboss.dna.graph.request.GetWorkspacesRequest;
+import org.jboss.dna.graph.request.LockBranchRequest;
import org.jboss.dna.graph.request.MoveBranchRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
@@ -48,6 +49,7 @@
import org.jboss.dna.graph.request.RenameNodeRequest;
import org.jboss.dna.graph.request.Request;
import org.jboss.dna.graph.request.SetPropertyRequest;
+import org.jboss.dna.graph.request.UnlockBranchRequest;
import org.jboss.dna.graph.request.UpdatePropertiesRequest;
import org.jboss.dna.graph.request.VerifyNodeExistsRequest;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
@@ -356,6 +358,30 @@
/**
* {@inheritDoc}
*
+ * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.LockBranchRequest)
+ */
+ @Override
+ public void process( LockBranchRequest request ) {
+ logger.log(level, GraphI18n.executingRequest, request);
+ delegate.process(request);
+ logger.log(level, GraphI18n.executedRequest, request);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.UnlockBranchRequest)
+ */
+ @Override
+ public void process( UnlockBranchRequest request ) {
+ logger.log(level, GraphI18n.executingRequest, request);
+ delegate.process(request);
+ logger.log(level, GraphI18n.executedRequest, request);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.Request)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/RequestProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/RequestProcessor.java 2009-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/RequestProcessor.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -37,6 +37,8 @@
import org.jboss.dna.graph.GraphI18n;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.cache.CachePolicy;
+import org.jboss.dna.graph.connector.LockFailedException;
+import org.jboss.dna.graph.connector.RepositorySourceCapabilities;
import org.jboss.dna.graph.observe.Changes;
import org.jboss.dna.graph.observe.Observer;
import org.jboss.dna.graph.property.DateTime;
@@ -57,6 +59,7 @@
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
import org.jboss.dna.graph.request.GetWorkspacesRequest;
import org.jboss.dna.graph.request.InvalidRequestException;
+import org.jboss.dna.graph.request.LockBranchRequest;
import org.jboss.dna.graph.request.MoveBranchRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
@@ -69,6 +72,7 @@
import org.jboss.dna.graph.request.RenameNodeRequest;
import org.jboss.dna.graph.request.Request;
import org.jboss.dna.graph.request.SetPropertyRequest;
+import org.jboss.dna.graph.request.UnlockBranchRequest;
import org.jboss.dna.graph.request.UnsupportedRequestException;
import org.jboss.dna.graph.request.UpdatePropertiesRequest;
import org.jboss.dna.graph.request.UpdateValuesRequest;
@@ -251,6 +255,10 @@
process((UpdatePropertiesRequest)request);
} else if (request instanceof VerifyNodeExistsRequest) {
process((VerifyNodeExistsRequest)request);
+ } else if (request instanceof LockBranchRequest) {
+ process((LockBranchRequest)request);
+ } else if (request instanceof UnlockBranchRequest) {
+ process((UnlockBranchRequest)request);
} else if (request instanceof VerifyWorkspaceRequest) {
process((VerifyWorkspaceRequest)request);
} else if (request instanceof GetWorkspacesRequest) {
@@ -779,7 +787,7 @@
Property property = readProperty.getProperty();
List<Object> actualRemovedValues = new ArrayList<Object>(request.removedValues().size());
List<Object> newValues = property == null ? new LinkedList<Object>() : new LinkedList<Object>(
- Arrays.asList(property.getValuesAsArray()));
+ Arrays.asList(property.getValuesAsArray()));
// Calculate what the new values should be
for (Object removedValue : request.removedValues()) {
for (Iterator<Object> iter = newValues.iterator(); iter.hasNext();) {
@@ -793,7 +801,7 @@
newValues.addAll(request.addedValues());
Property newProperty = getExecutionContext().getPropertyFactory().create(propertyName, newValues);
-
+
// Update the current values
SetPropertyRequest setProperty = new SetPropertyRequest(on, workspaceName, newProperty);
process(setProperty);
@@ -845,6 +853,35 @@
}
/**
+ * Process a request to lock a node or branch within a workspace
+ * <p>
+ * The default implementation of this method does nothing, as most connectors will not support locking (as defined in
+ * {@link RepositorySourceCapabilities#supportsLocks()}). Any implementation of this method should do nothing if the request
+ * is null.
+ * </p>
+ * <p>
+ * Implementations that do support locking should throw a {@link LockFailedException} if the request could not be fulfilled.
+ * </p>
+ *
+ * @param request the request
+ */
+ public void process( LockBranchRequest request ) {
+ }
+
+ /**
+ * Process a request to unlock a node or branch within a workspace
+ * <p>
+ * The default implementation of this method does nothing, as most connectors will not support locking (as defined in
+ * {@link RepositorySourceCapabilities#supportsLocks()}). Any implementation of this method should do nothing if the request
+ * is null.
+ * </p>
+ *
+ * @param request the request
+ */
+ public void process( UnlockBranchRequest request ) {
+ }
+
+ /**
* A class that represents a location at a known depth
*
* @author Randall Hauch
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-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2009-10-21 22:12:10 UTC (rev 1304)
@@ -77,6 +77,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}"
+couldNotAcquireLock = Could not acquire lock on the node at "{0}" in workspace "{1}"
# In-memory connector
inMemoryNodeDoesNotExist = Could not find an existing node at {0}
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-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -63,6 +63,7 @@
import org.jboss.dna.graph.request.DeleteBranchRequest;
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
import org.jboss.dna.graph.request.GetWorkspacesRequest;
+import org.jboss.dna.graph.request.LockBranchRequest;
import org.jboss.dna.graph.request.MoveBranchRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
@@ -72,11 +73,13 @@
import org.jboss.dna.graph.request.ReadPropertyRequest;
import org.jboss.dna.graph.request.Request;
import org.jboss.dna.graph.request.SetPropertyRequest;
+import org.jboss.dna.graph.request.UnlockBranchRequest;
import org.jboss.dna.graph.request.UpdatePropertiesRequest;
import org.jboss.dna.graph.request.VerifyNodeExistsRequest;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest.CloneConflictBehavior;
import org.jboss.dna.graph.request.CreateWorkspaceRequest.CreateConflictBehavior;
+import org.jboss.dna.graph.request.LockBranchRequest.LockScope;
import org.jboss.dna.graph.request.processor.RequestProcessor;
import org.junit.Before;
import org.junit.Test;
@@ -206,6 +209,24 @@
assertThat(delete.at(), is(at));
}
+ protected void assertNextRequestIsLock( Location at,
+ LockScope lockScope,
+ long lockTimeout ) {
+ Request request = executedRequests.poll();
+ assertThat(request, is(instanceOf(LockBranchRequest.class)));
+ LockBranchRequest lock = (LockBranchRequest)request;
+ assertThat(lock.at(), is(at));
+ assertThat(lock.lockScope(), is(lockScope));
+ assertThat(lock.lockTimeoutInMillis(), is(lockTimeout));
+ }
+
+ protected void assertNextRequestIsUnlock( Location at ) {
+ Request request = executedRequests.poll();
+ assertThat(request, is(instanceOf(UnlockBranchRequest.class)));
+ UnlockBranchRequest unlock = (UnlockBranchRequest)request;
+ assertThat(unlock.at(), is(at));
+ }
+
protected void assertNextRequestIsCreate( Location parent,
String child,
Property... properties ) {
@@ -1072,6 +1093,24 @@
graph.useWorkspace("something");
}
+ @Test
+ public void shouldLockNodeButNotDescendants() {
+ graph.lock(validPath).only().withDefaultTimeout();
+ assertNextRequestIsLock(Location.create(validPath), LockScope.SELF_ONLY, 0);
+ }
+
+ @Test
+ public void shouldLockNodeAndItsDescendants() {
+ graph.lock(validPath).andItsDescendants().withTimeoutOf(12345);
+ assertNextRequestIsLock(Location.create(validPath), LockScope.SELF_AND_DESCENDANTS, 12345);
+ }
+
+ @Test
+ public void shouldUnlockNode() {
+ graph.unlock(validPath);
+ assertNextRequestIsUnlock(Location.create(validPath));
+ }
+
// ----------------------------------------------------------------------------------------------------------------
// Implementation of RepositoryConnection and RequestProcessor for tests
// ----------------------------------------------------------------------------------------------------------------
@@ -1136,6 +1175,18 @@
}
@Override
+ public void process( LockBranchRequest request ) {
+ // Just update the actual location
+ request.setActualLocation(actualLocationOf(request.at()));
+ }
+
+ @Override
+ public void process( UnlockBranchRequest request ) {
+ // Just update the actual location
+ request.setActualLocation(actualLocationOf(request.at()));
+ }
+
+ @Override
public void process( MoveBranchRequest request ) {
// Just update the actual location ...
Name newName = request.desiredName();
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/MockRepositoryRequestProcessor.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/MockRepositoryRequestProcessor.java 2009-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/MockRepositoryRequestProcessor.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -25,6 +25,7 @@
import java.util.Queue;
import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.request.CloneBranchRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
import org.jboss.dna.graph.request.CopyBranchRequest;
@@ -33,6 +34,7 @@
import org.jboss.dna.graph.request.DeleteBranchRequest;
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
import org.jboss.dna.graph.request.GetWorkspacesRequest;
+import org.jboss.dna.graph.request.LockBranchRequest;
import org.jboss.dna.graph.request.MoveBranchRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
@@ -45,6 +47,7 @@
import org.jboss.dna.graph.request.RenameNodeRequest;
import org.jboss.dna.graph.request.Request;
import org.jboss.dna.graph.request.SetPropertyRequest;
+import org.jboss.dna.graph.request.UnlockBranchRequest;
import org.jboss.dna.graph.request.UpdatePropertiesRequest;
import org.jboss.dna.graph.request.VerifyNodeExistsRequest;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
@@ -55,7 +58,9 @@
*/
public class MockRepositoryRequestProcessor extends RequestProcessor {
- private Queue<Request> processed;
+ private static final String DEFAULT_WORKSPACE_NAME = "default";
+ private final Queue<Request> processed;
+ private final Location defaultWorkspaceRoot;
/**
* @param sourceName
@@ -67,7 +72,9 @@
Queue<Request> processed ) {
super(sourceName, context, null);
assert processed != null;
+
this.processed = processed;
+ this.defaultWorkspaceRoot = Location.create(context.getValueFactories().getPathFactory().createRootPath());
}
protected void record( Request request ) {
@@ -82,6 +89,10 @@
@Override
public void process( VerifyWorkspaceRequest request ) {
record(request);
+
+ // Need to add this loopback in so we can use this with JCR layer test cases
+ request.setActualWorkspaceName(request.getActualWorkspaceName() == null ? DEFAULT_WORKSPACE_NAME : request.getActualWorkspaceName());
+ request.setActualRootLocation(request.getActualLocationOfRoot() == null ? defaultWorkspaceRoot : request.getActualLocationOfRoot());
}
/**
@@ -177,6 +188,26 @@
/**
* {@inheritDoc}
*
+ * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.LockBranchRequest)
+ */
+ @Override
+ public void process( LockBranchRequest request ) {
+ record(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.UnlockBranchRequest)
+ */
+ @Override
+ public void process( UnlockBranchRequest request ) {
+ record(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.ReadAllChildrenRequest)
*/
@Override
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-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/test/WritableConnectorTest.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -83,6 +83,10 @@
super.afterEach();
}
+ private boolean supportsLocks() {
+ return source.getCapabilities().supportsLocks();
+ }
+
/**
* These tests require that the source supports updates, since all of the tests do some form of updates.
*/
@@ -120,20 +124,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")
- .and()
- .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").and().execute();
// Now look up the root node ...
Node root = graph.getNodeAt("/");
assertThat(root, is(notNullValue()));
@@ -886,20 +879,12 @@
graph.create("/newUuids").and();
// Copy once to get the UUID into the default workspace
// graph.copy("/node1/node1/node1").failingIfUuidsMatch().fromWorkspace(workspaceName).to("/newUuids/node1");
- graph.clone("/node1/node1/node1")
- .fromWorkspace(workspaceName)
- .as(name("node1"))
- .into("/newUuids")
- .failingIfAnyUuidsMatch();
+ graph.clone("/node1/node1/node1").fromWorkspace(workspaceName).as(name("node1")).into("/newUuids").failingIfAnyUuidsMatch();
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");
- graph.clone("/node1/node1/node1")
- .fromWorkspace(workspaceName)
- .as(name("shouldNotWork"))
- .into("/newUuids")
- .failingIfAnyUuidsMatch();
+ graph.clone("/node1/node1/node1").fromWorkspace(workspaceName).as(name("shouldNotWork")).into("/newUuids").failingIfAnyUuidsMatch();
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) {
@@ -931,11 +916,7 @@
graph.create("/newUuids").and();
// Copy once to get the UUID into the default workspace
// graph.copy("/node1").replacingExistingNodesWithSameUuids().fromWorkspace(workspaceName).to("/newUuids/node1");
- graph.clone("/node1")
- .fromWorkspace(workspaceName)
- .as(name("node1"))
- .into("/newUuids")
- .replacingExistingNodesWithSameUuids();
+ graph.clone("/node1").fromWorkspace(workspaceName).as(name("node1")).into("/newUuids").replacingExistingNodesWithSameUuids();
// Make sure that the node wasn't moved by the clone
graph.useWorkspace(workspaceName);
@@ -948,11 +929,7 @@
// 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");
- graph.clone("/node1")
- .fromWorkspace(workspaceName)
- .as(name("otherNode"))
- .into("/newUuids")
- .replacingExistingNodesWithSameUuids();
+ graph.clone("/node1").fromWorkspace(workspaceName).as(name("otherNode")).into("/newUuids").replacingExistingNodesWithSameUuids();
/*
* Focus on testing node structure, since shouldCopyNodeWithChildren tests that properties get copied
@@ -1009,11 +986,7 @@
// Copy again to test the behavior now that the UUIDs are already in the default workspace
// This should remove /segmentTestUuids/node1[1]
- graph.clone("/node1")
- .fromWorkspace(workspaceName)
- .as(segment("node1[1]"))
- .into("/segmentTestUuids")
- .replacingExistingNodesWithSameUuids();
+ graph.clone("/node1").fromWorkspace(workspaceName).as(segment("node1[1]")).into("/segmentTestUuids").replacingExistingNodesWithSameUuids();
/*
* Focus on testing node structure, since shouldCopyNodeWithChildren tests that properties get copied
@@ -1955,4 +1928,25 @@
assertThat(subgraph.getNode("node1"), hasProperty("property1", "The quick brown fox jumped over the moon. What? "));
}
+ @Test
+ public void shouldLockNode() {
+ if (!supportsLocks()) return;
+
+ fail("Need to add test body here");
+ }
+
+ @Test
+ public void shouldNotAllowMultipleConcurrentLocksOnSameNode() {
+ if (!supportsLocks()) return;
+
+ fail("Need to add test body here");
+ }
+
+ @Test
+ public void shouldUnlockNode() {
+ if (!supportsLocks()) return;
+
+ fail("Need to add test body here");
+ }
+
}
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-10-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/AbstractJcrNode.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -1368,7 +1368,7 @@
nodesToVisit.add(nodeInfo());
while (!nodesToVisit.isEmpty()) {
- Node<JcrNodePayload, JcrPropertyPayload> node = nodesToVisit.get(nodesToVisit.size() - 1);
+ Node<JcrNodePayload, JcrPropertyPayload> node = nodesToVisit.remove(nodesToVisit.size() - 1);
if (session().workspace().lockManager().lockFor(node.getLocation()) != null) throw new LockException(
JcrI18n.parentAlreadyLocked.text(this.location,
node.getLocation()));
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-21 17:29:30 UTC (rev 1303)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/WorkspaceLockManager.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -4,6 +4,7 @@
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import javax.jcr.Item;
import javax.jcr.Node;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
@@ -14,6 +15,8 @@
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.LockFailedException;
+import org.jboss.dna.graph.connector.RepositorySourceCapabilities;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.PathNotFoundException;
@@ -80,7 +83,7 @@
throw new RepositoryException(JcrI18n.uuidRequiredForLock.text(nodeLocation));
}
- DnaLock lock = new DnaLock(lockOwner, lockUuid, nodeUuid, isDeep, isSessionScoped);
+ DnaLock lock = createLock(lockOwner, lockUuid, nodeUuid, isDeep, isSessionScoped);
Graph.Batch batch = repository.createSystemGraph().batch();
@@ -110,15 +113,73 @@
false);
editor.setProperty(JcrLexicon.LOCK_IS_DEEP, (JcrValue)cache.session().getValueFactory().createValue(isDeep), false);
- // Write them directly to the underlying graph
- repository.createWorkspaceGraph(workspaceName).set(lockOwnerProp, lockIsDeepProp).on(nodeUuid);
-
+ lockNodeInRepository(nodeUuid, lockOwnerProp, lockIsDeepProp, lock, isDeep);
workspaceLocksByNodeUuid.put(nodeUuid, lock);
return lock;
}
+ /* Factory method added to facilitate mocked testing */
+ DnaLock createLock( String lockOwner,
+ UUID lockUuid,
+ UUID nodeUuid,
+ boolean isDeep,
+ boolean isSessionScoped ) {
+ return new DnaLock(lockOwner, lockUuid, nodeUuid, isDeep, isSessionScoped);
+ }
+
/**
+ * Marks the node as locked in the underlying repository with an immediate write (that is, the write is not part of the JCR
+ * session scope and cannot be "rolled back" with a refresh at the {@link Session#refresh(boolean) session} or
+ * {@link Item#refresh(boolean) item} level.
+ * <p>
+ * This method will also attempt to {@link Graph#lock(Location) lock the node in the underlying repository}. If the underlying
+ * repository {@link RepositorySourceCapabilities#supportsLocks() supports locks} and {@link LockFailedException the lock
+ * attempt fails}, this method will cancel the lock attempt by calling {@link #unlock(DnaLock)} and will throw a {@code
+ * RepositoryException}.
+ * </p>
+ * <p>
+ * This method does not modify the system graph. In other words, it will not create the record for the lock in the {@code
+ * /jcr:system/dna:locks} subgraph.
+ * </p>
+ *
+ * @param nodeUuid the UUID of the node to lock
+ * @param lockOwnerProp an existing property with name {@link JcrLexicon#LOCK_OWNER} and the value being the name of the lock
+ * owner
+ * @param lockIsDeepProp an existing property with name {@link JcrLexicon#LOCK_IS_DEEP} and the value being {@code true} if
+ * the lock should include all descendants of the locked node or {@code false} if the lock should only include the
+ * specified node and not its descendants
+ * @param lock the internal lock representation
+ * @param isDeep {@code true} if the lock should include all descendants of the locked node or {@code false} if the lock
+ * should only include the specified node and not its descendants. This value is redundant with the lockIsDeep
+ * parameter, but is included separately as a minor performance optimization
+ * @throws RepositoryException if the repository in which the node represented by {@code nodeUuid} supports locking but
+ * signals that the lock for the node cannot be acquired
+ */
+ void lockNodeInRepository( UUID nodeUuid,
+ Property lockOwnerProp,
+ Property lockIsDeepProp,
+ DnaLock lock,
+ boolean isDeep ) throws RepositoryException {
+ // Write them directly to the underlying graph
+ Graph.Batch workspaceBatch = repository.createWorkspaceGraph(workspaceName).batch();
+ workspaceBatch.set(lockOwnerProp, lockIsDeepProp).on(nodeUuid);
+ if (isDeep) {
+ workspaceBatch.lock(nodeUuid).andItsDescendants().withDefaultTimeout();
+ } else {
+ workspaceBatch.lock(nodeUuid).only().withDefaultTimeout();
+ }
+ try {
+ workspaceBatch.execute();
+ } catch (LockFailedException lfe) {
+ // Attempt to lock node at the repo level failed - cancel lock
+ unlock(lock);
+ throw new RepositoryException(lfe);
+ }
+
+ }
+
+ /**
* Removes the provided lock, effectively unlocking the node to which the lock is associated.
*
* @param lock the lock to be removed
@@ -132,6 +193,9 @@
batch.delete(pathFactory.create(locksPath, pathFactory.createSegment(lock.getUuid().toString())));
batch.remove(JcrLexicon.LOCK_OWNER, JcrLexicon.LOCK_IS_DEEP).on(lock.nodeUuid);
batch.execute();
+
+ unlockNodeInRepository(lock);
+
workspaceLocksByNodeUuid.remove(lock.nodeUuid);
} catch (PathNotFoundException pnfe) {
/*
@@ -147,20 +211,58 @@
}
}
+ /**
+ * Removes the workspace record of the lock in the underlying repository. This method clears the {@code jcr:lockOwner} and
+ * {@code jcr:lockIsDeep} properties on the node and sends an {@link Graph#unlock(Location) unlock request} to the underlying
+ * repository to clear any locks that it is holding on the node.
+ * <p>
+ * This method does not modify the system graph. In other words, it will not remove the record for the lock in the {@code
+ * /jcr:system/dna:locks} subgraph.
+ * </p>
+ *
+ * @param lock
+ */
+ void unlockNodeInRepository( DnaLock lock ) {
+ Graph.Batch workspaceBatch = repository.createWorkspaceGraph(this.workspaceName).batch();
+
+ workspaceBatch.remove(JcrLexicon.LOCK_OWNER, JcrLexicon.LOCK_IS_DEEP).on(lock.nodeUuid);
+ workspaceBatch.unlock(lock.nodeUuid);
+
+ workspaceBatch.execute();
+ }
+
+ /**
+ * Checks whether the given lock token is currently held by any session by querying the lock record in the underlying
+ * repository.
+ *
+ * @param lockToken the lock token to check; may not be null
+ * @return true if a session currently holds the lock token, false otherwise
+ */
boolean isHeldBySession( String lockToken ) {
+ assert lockToken != null;
+
ValueFactory<Boolean> booleanFactory = context.getValueFactories().getBooleanFactory();
PathFactory pathFactory = context.getValueFactories().getPathFactory();
- org.jboss.dna.graph.Node lockNode = repository.createSystemGraph()
- .getNodeAt(pathFactory.create(locksPath,
- pathFactory.createSegment(lockToken)));
+ org.jboss.dna.graph.Node lockNode = repository.createSystemGraph().getNodeAt(pathFactory.create(locksPath,
+ pathFactory.createSegment(lockToken)));
return booleanFactory.create(lockNode.getProperty(DnaLexicon.IS_HELD_BY_SESSION).getFirstValue());
}
+ /**
+ * Updates the underlying repository directly (i.e., outside the scope of the {@link Session}) to mark the token for the given
+ * lock as being held (or not held) by some {@link Session}. Note that this method does not identify <i>which</i> (if any)
+ * session holds the token for the lock, just that <i>some</i> session holds the token for the lock.
+ *
+ * @param lockToken the lock token for which the "held" status should be modified; may not be null
+ * @param value the new value
+ */
void setHeldBySession( String lockToken,
boolean value ) {
+ assert lockToken != null;
+
PropertyFactory propFactory = context.getPropertyFactory();
PathFactory pathFactory = context.getValueFactories().getPathFactory();
@@ -194,13 +296,23 @@
* @return the corresponding lock, possibly null if there is no such lock
* @throws RepositoryException if there is a problem obtaining the information for a lock
*/
- DnaLock lockFor( Location nodeLocation ) throws RepositoryException {
+ DnaLock lockFor( Location nodeLocation ) {
UUID nodeUuid = uuidFor(nodeLocation);
if (nodeUuid == null) return null;
return workspaceLocksByNodeUuid.get(nodeUuid);
}
+ /**
+ * Returns the UUID that identifies the given location or {@code null} if the location does not have a UUID. The method
+ * returns the {@link Location#getUuid() default UUID} if it exists. If it does not, the method returns the value of the
+ * {@link JcrLexicon#UUID} property as a UUID. If the location does not contain that property, the method returns null.
+ *
+ * @param location the location for which the UUID should be returned
+ * @return the UUID that identifies the given location or {@code null} if the location does not have a UUID.
+ */
UUID uuidFor( Location location ) {
+ assert location != null;
+
if (location.getUuid() != null) return location.getUuid();
org.jboss.dna.graph.property.Property uuidProp = location.getIdProperty(JcrLexicon.UUID);
@@ -303,7 +415,7 @@
return sessionScoped;
}
- public void refresh() throws LockException, RepositoryException {
+ public void refresh() throws LockException {
if (getLockToken() == null) {
throw new LockException(JcrI18n.notLocked.text(node.location));
}
Added: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/WorkspaceLockManagerTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/WorkspaceLockManagerTest.java (rev 0)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/WorkspaceLockManagerTest.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -0,0 +1,156 @@
+package org.jboss.dna.jcr;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.stub;
+import java.util.LinkedList;
+import java.util.UUID;
+import javax.jcr.RepositoryException;
+import javax.security.auth.login.LoginException;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.Graph;
+import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.connector.MockRepositoryConnection;
+import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
+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.request.LockBranchRequest;
+import org.jboss.dna.graph.request.Request;
+import org.jboss.dna.graph.request.UnlockBranchRequest;
+import org.jboss.dna.graph.request.LockBranchRequest.LockScope;
+import org.jboss.dna.jcr.WorkspaceLockManager.DnaLock;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoAnnotations.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class WorkspaceLockManagerTest {
+
+ private Graph graph;
+ private ExecutionContext context;
+ private UUID validUuid;
+ private Location validLocation;
+ private String sourceName;
+ private String workspaceName;
+ private MockRepositoryConnection connection;
+ private LinkedList<Request> executedRequests;
+
+ private RepositoryNodeTypeManager repoTypeManager;
+ private WorkspaceLockManager workspaceLockManager;
+
+ @Mock
+ private RepositoryConnectionFactory connectionFactory;
+ @Mock
+ protected JcrRepository repository;
+
+ @Before
+ public void beforeEach() throws LoginException {
+ MockitoAnnotations.initMocks(this);
+ executedRequests = new LinkedList<Request>();
+ sourceName = "Source";
+ workspaceName = "default";
+ context = new ExecutionContext();
+ connection = new MockRepositoryConnection(sourceName, executedRequests);
+ stub(connectionFactory.createConnection(sourceName)).toReturn(connection);
+ graph = Graph.create(sourceName, connectionFactory, context);
+
+ validUuid = UUID.randomUUID();
+ validLocation = Location.create(validUuid);
+
+ // Stub out the repository, since we only need a few methods ...
+ repoTypeManager = new RepositoryNodeTypeManager(context);
+
+ PathFactory pathFactory = context.getValueFactories().getPathFactory();
+ stub(repository.getRepositoryTypeManager()).toReturn(repoTypeManager);
+ stub(repository.getRepositorySourceName()).toReturn(sourceName);
+ stub(repository.getPersistentRegistry()).toReturn(context.getNamespaceRegistry());
+ stub(repository.createWorkspaceGraph(anyString())).toAnswer(new Answer<Graph>() {
+ public Graph answer( InvocationOnMock invocation ) throws Throwable {
+ return graph;
+ }
+ });
+ stub(repository.createSystemGraph()).toAnswer(new Answer<Graph>() {
+ public Graph answer( InvocationOnMock invocation ) throws Throwable {
+ return graph;
+ }
+ });
+
+ Path locksPath = pathFactory.createAbsolutePath(JcrLexicon.SYSTEM, DnaLexicon.LOCKS);
+ workspaceLockManager = new WorkspaceLockManager(context, repository, workspaceName, locksPath);
+
+ stub(repository.getLockManager(anyString())).toAnswer(new Answer<WorkspaceLockManager>() {
+ public WorkspaceLockManager answer( InvocationOnMock invocation ) throws Throwable {
+ return workspaceLockManager;
+ }
+ });
+
+ executedRequests.clear();
+ }
+
+ protected Path createPath( String path ) {
+ return context.getValueFactories().getPathFactory().create(path);
+ }
+
+ protected Path createPath( Path parent,
+ String path ) {
+ return context.getValueFactories().getPathFactory().create(parent, path);
+ }
+
+ protected Name createName( String name ) {
+ return context.getValueFactories().getNameFactory().create(name);
+ }
+
+ protected Property createProperty( String name,
+ Object... values ) {
+ return context.getPropertyFactory().create(createName(name), values);
+ }
+
+ protected void assertNextRequestIsLock( Location at,
+ LockScope lockScope,
+ long lockTimeout ) {
+ Request request = executedRequests.poll();
+ assertThat(request, is(instanceOf(LockBranchRequest.class)));
+ LockBranchRequest lock = (LockBranchRequest)request;
+ assertThat(lock.at(), is(at));
+ assertThat(lock.lockScope(), is(lockScope));
+ assertThat(lock.lockTimeoutInMillis(), is(lockTimeout));
+ }
+
+ protected void assertNextRequestIsUnlock( Location at ) {
+ Request request = executedRequests.poll();
+ assertThat(request, is(instanceOf(UnlockBranchRequest.class)));
+ UnlockBranchRequest unlock = (UnlockBranchRequest)request;
+ assertThat(unlock.at(), is(at));
+ }
+
+ @Test
+ public void shouldCreateLockRequestWhenLockingNode() throws RepositoryException {
+ DnaLock lock = workspaceLockManager.createLock("testOwner", UUID.randomUUID(), validUuid, false, false);
+ PropertyFactory propFactory = context.getPropertyFactory();
+ String lockOwner = "testOwner";
+ boolean isDeep = false;
+
+ Property lockOwnerProp = propFactory.create(JcrLexicon.LOCK_OWNER, lockOwner);
+ Property lockIsDeepProp = propFactory.create(JcrLexicon.LOCK_IS_DEEP, isDeep);
+
+ workspaceLockManager.lockNodeInRepository(validUuid, lockOwnerProp, lockIsDeepProp, lock, isDeep);
+
+ assertNextRequestIsLock(validLocation, LockScope.SELF_ONLY, 0);
+ }
+
+ @Test
+ public void shouldCreateLockRequestWhenUnlockingNode() {
+ DnaLock lock = workspaceLockManager.createLock("testOwner", UUID.randomUUID(), validUuid, false, false);
+ workspaceLockManager.unlockNodeInRepository(lock);
+
+ assertNextRequestIsUnlock(validLocation);
+ }
+
+}
Property changes on: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/WorkspaceLockManagerTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java
===================================================================
--- trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java 2009-10-21 17:29:30 UTC (rev 1303)
+++ trunk/extensions/dna-connector-infinispan/src/main/java/org/jboss/dna/connector/infinispan/InfinispanRepository.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -4,10 +4,12 @@
import org.infinispan.Cache;
import org.infinispan.manager.CacheManager;
import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.LockFailedException;
import org.jboss.dna.graph.connector.map.AbstractMapWorkspace;
import org.jboss.dna.graph.connector.map.MapNode;
import org.jboss.dna.graph.connector.map.MapRepository;
import org.jboss.dna.graph.connector.map.MapWorkspace;
+import org.jboss.dna.graph.request.LockBranchRequest.LockScope;
/**
* The repository that uses an Infinispan instance.
@@ -80,6 +82,18 @@
assert nodeUuid != null;
return workspaceCache.get(nodeUuid);
}
+
+ @Override
+ public void lockNode( MapNode node,
+ LockScope lockScope,
+ long lockTimeoutInMillis ) throws LockFailedException {
+ // Locking is not supported by this connector
+ }
+
+ @Override
+ public void unlockNode( MapNode node ) {
+ // Locking is not supported by this connector
+ }
}
}
Modified: trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java
===================================================================
--- trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java 2009-10-21 17:29:30 UTC (rev 1303)
+++ trunk/extensions/dna-connector-jbosscache/src/main/java/org/jboss/dna/connector/jbosscache/JBossCacheRepository.java 2009-10-21 22:12:10 UTC (rev 1304)
@@ -5,10 +5,12 @@
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.connector.LockFailedException;
import org.jboss.dna.graph.connector.map.AbstractMapWorkspace;
import org.jboss.dna.graph.connector.map.MapNode;
import org.jboss.dna.graph.connector.map.MapRepository;
import org.jboss.dna.graph.connector.map.MapWorkspace;
+import org.jboss.dna.graph.request.LockBranchRequest.LockScope;
/**
* A repository implementation that uses JBoss Cache.
@@ -81,6 +83,19 @@
assert nodeUuid != null;
return workspaceNode.get(nodeUuid);
}
+
+ @Override
+ public void lockNode( MapNode node,
+ LockScope lockScope,
+ long lockTimeoutInMillis ) throws LockFailedException {
+ // Locking is not supported by this connector
+ }
+
+ @Override
+ public void unlockNode( MapNode node ) {
+ // Locking is not supported by this connector
+ }
+
}
}
16 years, 2 months
DNA SVN: r1303 - trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-10-21 13:29:30 -0400 (Wed, 21 Oct 2009)
New Revision: 1303
Removed:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java
Log:
DNA-467 Removed optimization rule that combined set criteria (e.g., 'IN (1,2,3)'), since it was AND-ing together OR-ed criteria and was thus invalid.
Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java 2009-10-21 17:29:08 UTC (rev 1302)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java 2009-10-21 17:29:30 UTC (rev 1303)
@@ -1,113 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.graph.query.optimize;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.graph.query.QueryContext;
-import org.jboss.dna.graph.query.model.Constraint;
-import org.jboss.dna.graph.query.model.SetCriteria;
-import org.jboss.dna.graph.query.plan.PlanNode;
-import org.jboss.dna.graph.query.plan.PlanNode.Property;
-import org.jboss.dna.graph.query.plan.PlanNode.Type;
-
-/**
- * An {@link OptimizerRule optimizer rule} that merges SELECT nodes that have {@link SetCriteria} applied to the same column on
- * the same selector.
- *
- * @param <SimilarityType> the type used to compare and identify similar nodes
- * @param <ConstraintType> the concrete type of Constraint objects that are being merged
- */
-@Immutable
-public abstract class AbstractMergeSelectNodes<SimilarityType, ConstraintType extends Constraint> implements OptimizerRule {
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.query.optimize.OptimizerRule#execute(org.jboss.dna.graph.query.QueryContext,
- * org.jboss.dna.graph.query.plan.PlanNode, java.util.LinkedList)
- */
- @SuppressWarnings( "unchecked" )
- public PlanNode execute( QueryContext context,
- PlanNode plan,
- LinkedList<OptimizerRule> ruleStack ) {
- Map<SimilarityType, LinkedList<PlanNode>> mergeables = new HashMap<SimilarityType, LinkedList<PlanNode>>();
- for (PlanNode source : plan.findAllAtOrBelow(Type.SOURCE)) {
- // Walk up from the SOURCE and look for all SELECT nodes ...
- PlanNode node = source.getParent();
- while (node != null && node.is(Type.SELECT)) {
- Constraint constraint = node.getProperty(Property.SELECT_CRITERIA, Constraint.class);
- SimilarityType operand = getSimilarityKey(constraint);
- if (operand != null) {
- LinkedList<PlanNode> nodes = mergeables.get(operand);
- if (nodes == null) {
- nodes = new LinkedList<PlanNode>();
- mergeables.put(operand, nodes);
- }
- nodes.addFirst(node); // So that the list is in the downward order they appear in the plan
- }
- node = node.getParent();
- }
-
- // Merge all mergeable SELECT nodes ...
- for (LinkedList<PlanNode> mergeable : mergeables.values()) {
- if (mergeable.size() > 1) {
- Iterator<PlanNode> iter = mergeable.iterator();
- PlanNode firstSelect = iter.next();
- Constraint constraint = firstSelect.getProperty(Property.SELECT_CRITERIA, Constraint.class);
- while (iter.hasNext()) {
- PlanNode nextSelect = iter.next();
- Constraint nextConstraint = nextSelect.getProperty(Property.SELECT_CRITERIA, Constraint.class);
- constraint = merge((ConstraintType)constraint, (ConstraintType)nextConstraint);
- nextSelect.extractFromParent();
- }
- firstSelect.setProperty(Property.SELECT_CRITERIA, constraint);
- }
- }
- mergeables.clear();
- }
- return plan;
- }
-
- /**
- * Obtain the similarity key that will be used to determine whether two SELECT nodes should be merged.
- *
- * @param constraint the constraint from the SELECT node
- * @return the similarity key, or null if the constraint should not be merged
- */
- protected abstract SimilarityType getSimilarityKey( Constraint constraint );
-
- /**
- * Merge the two constraints.
- *
- * @param firstConstraint the first constraint
- * @param secondConstraint the second constraint
- * @return the merged constraint
- */
- protected abstract Constraint merge( ConstraintType firstConstraint,
- ConstraintType secondConstraint );
-}
Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java 2009-10-21 17:29:08 UTC (rev 1302)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java 2009-10-21 17:29:30 UTC (rev 1303)
@@ -1,89 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.graph.query.optimize;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.graph.query.model.Constraint;
-import org.jboss.dna.graph.query.model.DynamicOperand;
-import org.jboss.dna.graph.query.model.SetCriteria;
-import org.jboss.dna.graph.query.model.StaticOperand;
-
-/**
- * An {@link OptimizerRule optimizer rule} that merges SELECT nodes that have {@link SetCriteria} applied to the same column on
- * the same selector.
- */
-@Immutable
-public class MergeSetCriteria extends AbstractMergeSelectNodes<DynamicOperand, SetCriteria> {
-
- public static final MergeSetCriteria INSTANCE = new MergeSetCriteria();
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.query.optimize.AbstractMergeSelectNodes#getSimilarityKey(org.jboss.dna.graph.query.model.Constraint)
- */
- @Override
- protected DynamicOperand getSimilarityKey( Constraint constraint ) {
- if (constraint instanceof SetCriteria) {
- // Look for the list of plan nodes for this operand ...
- return ((SetCriteria)constraint).getLeftOperand();
- }
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.query.optimize.AbstractMergeSelectNodes#merge(org.jboss.dna.graph.query.model.Constraint,
- * org.jboss.dna.graph.query.model.Constraint)
- */
- @Override
- protected Constraint merge( SetCriteria firstConstraint,
- SetCriteria secondConstraint ) {
- assert firstConstraint.getLeftOperand().equals(secondConstraint.getLeftOperand());
- Set<StaticOperand> allOperands = new HashSet<StaticOperand>();
- List<StaticOperand> orderedOperands = new ArrayList<StaticOperand>(firstConstraint.getRightOperands());
- allOperands.addAll(firstConstraint.getRightOperands());
- for (StaticOperand second : secondConstraint.getRightOperands()) {
- if (allOperands.add(second)) {
- orderedOperands.add(second);
- }
- }
- return new SetCriteria(firstConstraint.getLeftOperand(), orderedOperands);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return getClass().getSimpleName();
- }
-}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java 2009-10-21 17:29:08 UTC (rev 1302)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java 2009-10-21 17:29:30 UTC (rev 1303)
@@ -69,7 +69,6 @@
*/
protected void populateRuleStack( LinkedList<OptimizerRule> ruleStack,
PlanHints hints ) {
- ruleStack.addFirst(MergeSetCriteria.INSTANCE);
if (hints.hasJoin) {
ruleStack.addFirst(ChooseJoinAlgorithm.USE_ONLY_NESTED_JOIN_ALGORITHM);
ruleStack.addFirst(RewriteIdentityJoins.INSTANCE);
16 years, 2 months
DNA SVN: r1302 - trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-10-21 13:29:08 -0400 (Wed, 21 Oct 2009)
New Revision: 1302
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java
Log:
Fixed merge conflicts
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java 2009-10-21 17:29:08 UTC (rev 1302)
@@ -0,0 +1,113 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.query.optimize;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.query.QueryContext;
+import org.jboss.dna.graph.query.model.Constraint;
+import org.jboss.dna.graph.query.model.SetCriteria;
+import org.jboss.dna.graph.query.plan.PlanNode;
+import org.jboss.dna.graph.query.plan.PlanNode.Property;
+import org.jboss.dna.graph.query.plan.PlanNode.Type;
+
+/**
+ * An {@link OptimizerRule optimizer rule} that merges SELECT nodes that have {@link SetCriteria} applied to the same column on
+ * the same selector.
+ *
+ * @param <SimilarityType> the type used to compare and identify similar nodes
+ * @param <ConstraintType> the concrete type of Constraint objects that are being merged
+ */
+@Immutable
+public abstract class AbstractMergeSelectNodes<SimilarityType, ConstraintType extends Constraint> implements OptimizerRule {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.query.optimize.OptimizerRule#execute(org.jboss.dna.graph.query.QueryContext,
+ * org.jboss.dna.graph.query.plan.PlanNode, java.util.LinkedList)
+ */
+ @SuppressWarnings( "unchecked" )
+ public PlanNode execute( QueryContext context,
+ PlanNode plan,
+ LinkedList<OptimizerRule> ruleStack ) {
+ Map<SimilarityType, LinkedList<PlanNode>> mergeables = new HashMap<SimilarityType, LinkedList<PlanNode>>();
+ for (PlanNode source : plan.findAllAtOrBelow(Type.SOURCE)) {
+ // Walk up from the SOURCE and look for all SELECT nodes ...
+ PlanNode node = source.getParent();
+ while (node != null && node.is(Type.SELECT)) {
+ Constraint constraint = node.getProperty(Property.SELECT_CRITERIA, Constraint.class);
+ SimilarityType operand = getSimilarityKey(constraint);
+ if (operand != null) {
+ LinkedList<PlanNode> nodes = mergeables.get(operand);
+ if (nodes == null) {
+ nodes = new LinkedList<PlanNode>();
+ mergeables.put(operand, nodes);
+ }
+ nodes.addFirst(node); // So that the list is in the downward order they appear in the plan
+ }
+ node = node.getParent();
+ }
+
+ // Merge all mergeable SELECT nodes ...
+ for (LinkedList<PlanNode> mergeable : mergeables.values()) {
+ if (mergeable.size() > 1) {
+ Iterator<PlanNode> iter = mergeable.iterator();
+ PlanNode firstSelect = iter.next();
+ Constraint constraint = firstSelect.getProperty(Property.SELECT_CRITERIA, Constraint.class);
+ while (iter.hasNext()) {
+ PlanNode nextSelect = iter.next();
+ Constraint nextConstraint = nextSelect.getProperty(Property.SELECT_CRITERIA, Constraint.class);
+ constraint = merge((ConstraintType)constraint, (ConstraintType)nextConstraint);
+ nextSelect.extractFromParent();
+ }
+ firstSelect.setProperty(Property.SELECT_CRITERIA, constraint);
+ }
+ }
+ mergeables.clear();
+ }
+ return plan;
+ }
+
+ /**
+ * Obtain the similarity key that will be used to determine whether two SELECT nodes should be merged.
+ *
+ * @param constraint the constraint from the SELECT node
+ * @return the similarity key, or null if the constraint should not be merged
+ */
+ protected abstract SimilarityType getSimilarityKey( Constraint constraint );
+
+ /**
+ * Merge the two constraints.
+ *
+ * @param firstConstraint the first constraint
+ * @param secondConstraint the second constraint
+ * @return the merged constraint
+ */
+ protected abstract Constraint merge( ConstraintType firstConstraint,
+ ConstraintType secondConstraint );
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java 2009-10-21 17:29:08 UTC (rev 1302)
@@ -0,0 +1,89 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.query.optimize;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.query.model.Constraint;
+import org.jboss.dna.graph.query.model.DynamicOperand;
+import org.jboss.dna.graph.query.model.SetCriteria;
+import org.jboss.dna.graph.query.model.StaticOperand;
+
+/**
+ * An {@link OptimizerRule optimizer rule} that merges SELECT nodes that have {@link SetCriteria} applied to the same column on
+ * the same selector.
+ */
+@Immutable
+public class MergeSetCriteria extends AbstractMergeSelectNodes<DynamicOperand, SetCriteria> {
+
+ public static final MergeSetCriteria INSTANCE = new MergeSetCriteria();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.query.optimize.AbstractMergeSelectNodes#getSimilarityKey(org.jboss.dna.graph.query.model.Constraint)
+ */
+ @Override
+ protected DynamicOperand getSimilarityKey( Constraint constraint ) {
+ if (constraint instanceof SetCriteria) {
+ // Look for the list of plan nodes for this operand ...
+ return ((SetCriteria)constraint).getLeftOperand();
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.query.optimize.AbstractMergeSelectNodes#merge(org.jboss.dna.graph.query.model.Constraint,
+ * org.jboss.dna.graph.query.model.Constraint)
+ */
+ @Override
+ protected Constraint merge( SetCriteria firstConstraint,
+ SetCriteria secondConstraint ) {
+ assert firstConstraint.getLeftOperand().equals(secondConstraint.getLeftOperand());
+ Set<StaticOperand> allOperands = new HashSet<StaticOperand>();
+ List<StaticOperand> orderedOperands = new ArrayList<StaticOperand>(firstConstraint.getRightOperands());
+ allOperands.addAll(firstConstraint.getRightOperands());
+ for (StaticOperand second : secondConstraint.getRightOperands()) {
+ if (allOperands.add(second)) {
+ orderedOperands.add(second);
+ }
+ }
+ return new SetCriteria(firstConstraint.getLeftOperand(), orderedOperands);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java 2009-10-21 17:21:57 UTC (rev 1301)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java 2009-10-21 17:29:08 UTC (rev 1302)
@@ -69,6 +69,7 @@
*/
protected void populateRuleStack( LinkedList<OptimizerRule> ruleStack,
PlanHints hints ) {
+ ruleStack.addFirst(MergeSetCriteria.INSTANCE);
if (hints.hasJoin) {
ruleStack.addFirst(ChooseJoinAlgorithm.USE_ONLY_NESTED_JOIN_ALGORITHM);
ruleStack.addFirst(RewriteIdentityJoins.INSTANCE);
16 years, 2 months
DNA SVN: r1301 - trunk/dna-jcr/src/main/java/org/jboss/dna/jcr.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-10-21 13:21:57 -0400 (Wed, 21 Oct 2009)
New Revision: 1301
Modified:
trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/WorkspaceLockManager.java
Log:
Corrected compiler warnings and JavaDoc errors
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-21 17:02:40 UTC (rev 1300)
+++ trunk/dna-jcr/src/main/java/org/jboss/dna/jcr/WorkspaceLockManager.java 2009-10-21 17:21:57 UTC (rev 1301)
@@ -72,14 +72,14 @@
boolean isDeep,
boolean isSessionScoped ) throws RepositoryException {
assert nodeLocation != null;
-
+
UUID lockUuid = UUID.randomUUID();
UUID nodeUuid = uuidFor(nodeLocation);
if (nodeUuid == null) {
throw new RepositoryException(JcrI18n.uuidRequiredForLock.text(nodeLocation));
}
-
+
DnaLock lock = new DnaLock(lockOwner, lockUuid, nodeUuid, isDeep, isSessionScoped);
Graph.Batch batch = repository.createSystemGraph().batch();
@@ -95,8 +95,8 @@
propFactory.create(DnaLexicon.WORKSPACE, workspaceName),
propFactory.create(DnaLexicon.LOCKED_NODE, 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),
+ // This gets set after the lock succeeds and the lock token gets added to the session
+ propFactory.create(DnaLexicon.IS_HELD_BY_SESSION, false),
lockOwnerProp,
lockIsDeepProp).ifAbsent().and();
batch.execute();
@@ -129,7 +129,7 @@
Graph.Batch batch = repository.createSystemGraph().batch();
- batch.delete(pathFactory.create(locksPath, pathFactory.createSegment(lock.lockUuid.toString())));
+ batch.delete(pathFactory.create(locksPath, pathFactory.createSegment(lock.getUuid().toString())));
batch.remove(JcrLexicon.LOCK_OWNER, JcrLexicon.LOCK_IS_DEEP).on(lock.nodeUuid);
batch.execute();
workspaceLocksByNodeUuid.remove(lock.nodeUuid);
@@ -151,22 +151,24 @@
ValueFactory<Boolean> booleanFactory = context.getValueFactories().getBooleanFactory();
PathFactory pathFactory = context.getValueFactories().getPathFactory();
- org.jboss.dna.graph.Node lockNode = repository.createSystemGraph().getNodeAt(pathFactory.create(locksPath,
- pathFactory.createSegment(lockToken)));
+ org.jboss.dna.graph.Node lockNode = repository.createSystemGraph()
+ .getNodeAt(pathFactory.create(locksPath,
+ pathFactory.createSegment(lockToken)));
return booleanFactory.create(lockNode.getProperty(DnaLexicon.IS_HELD_BY_SESSION).getFirstValue());
-
+
}
-
+
void setHeldBySession( String lockToken,
boolean value ) {
PropertyFactory propFactory = context.getPropertyFactory();
PathFactory pathFactory = context.getValueFactories().getPathFactory();
- repository.createSystemGraph().set(propFactory.create(DnaLexicon.IS_HELD_BY_SESSION, value)).on(pathFactory.create(locksPath,
- pathFactory.createSegment(lockToken)));
+ repository.createSystemGraph()
+ .set(propFactory.create(DnaLexicon.IS_HELD_BY_SESSION, value))
+ .on(pathFactory.create(locksPath, pathFactory.createSegment(lockToken)));
}
-
+
/**
* Returns the lock that corresponds to the given lock token
*
@@ -188,17 +190,17 @@
/**
* Returns the lock that corresponds to the given UUID
*
- * @param nodeUuid the node UUID
- * @return the corresponding lock, possibly null
+ * @param nodeLocation the node UUID
+ * @return the corresponding lock, possibly null if there is no such lock
+ * @throws RepositoryException if there is a problem obtaining the information for a lock
*/
DnaLock lockFor( Location nodeLocation ) throws RepositoryException {
UUID nodeUuid = uuidFor(nodeLocation);
if (nodeUuid == null) return null;
return workspaceLocksByNodeUuid.get(nodeUuid);
}
-
- UUID uuidFor( Location location ) throws RepositoryException {
+ UUID uuidFor( Location location ) {
if (location.getUuid() != null) return location.getUuid();
org.jboss.dna.graph.property.Property uuidProp = location.getIdProperty(JcrLexicon.UUID);
@@ -246,10 +248,15 @@
this.sessionScoped = sessionScoped;
}
+ @SuppressWarnings( "synthetic-access" )
public boolean isLive() {
return workspaceLocksByNodeUuid.containsKey(nodeUuid);
}
+ public UUID getUuid() {
+ return lockUuid;
+ }
+
public boolean isDeep() {
return deep;
}
@@ -266,6 +273,7 @@
return lockUuid.toString();
}
+ @SuppressWarnings( "synthetic-access" )
public Lock lockFor( SessionCache cache ) throws RepositoryException {
final AbstractJcrNode node = cache.findJcrNode(Location.create(nodeUuid));
final JcrSession session = cache.session();
@@ -287,7 +295,7 @@
return deep;
}
- public boolean isLive() throws RepositoryException {
+ public boolean isLive() {
return workspaceLocksByNodeUuid.containsKey(nodeUuid);
}
16 years, 2 months
DNA SVN: r1300 - in trunk/dna-graph/src/main/java/org/jboss/dna/graph/query: optimize and 2 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-10-21 13:02:40 -0400 (Wed, 21 Oct 2009)
New Revision: 1300
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RaiseSelectCriteria.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Visitors.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/CopyCriteria.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/ReplaceViews.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanNode.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/process/QueryProcessor.java
Log:
DNA-467 Added query optimizer rule that raises criteria added because of a view but below a join, in case that same criteria could be applied to the other side of the join.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Visitors.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Visitors.java 2009-10-21 17:02:10 UTC (rev 1299)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Visitors.java 2009-10-21 17:02:40 UTC (rev 1300)
@@ -23,7 +23,6 @@
*/
package org.jboss.dna.graph.query.model;
-import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
@@ -33,7 +32,6 @@
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.ValueFactory;
/**
* A set of common visitors that can be reused or extended, and methods that provide easy construction and calling of visitors.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/CopyCriteria.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/CopyCriteria.java 2009-10-21 17:02:10 UTC (rev 1299)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/CopyCriteria.java 2009-10-21 17:02:40 UTC (rev 1300)
@@ -38,6 +38,7 @@
import org.jboss.dna.graph.query.model.JoinCondition;
import org.jboss.dna.graph.query.model.PropertyExistence;
import org.jboss.dna.graph.query.model.PropertyValue;
+import org.jboss.dna.graph.query.model.SameNodeJoinCondition;
import org.jboss.dna.graph.query.model.SelectorName;
import org.jboss.dna.graph.query.model.Visitable;
import org.jboss.dna.graph.query.model.Visitors;
@@ -98,10 +99,49 @@
node = node.getParent();
}
}
+
+ if (joinCondition instanceof EquiJoinCondition || joinCondition instanceof SameNodeJoinCondition) {
+ // Then for each side of the join ...
+ PlanNode left = join.getFirstChild();
+ PlanNode right = join.getLastChild();
+ copySelectNodes(context, left, right);
+ copySelectNodes(context, right, left);
+ }
}
return plan;
}
+ protected void copySelectNodes( QueryContext context,
+ PlanNode fromJoined,
+ PlanNode toJoined ) {
+ // Find all of the selectors used on the 'to' side ...
+ Set<SelectorName> toSelectors = new HashSet<SelectorName>();
+ for (PlanNode toNode : toJoined.findAllAtOrBelow()) {
+ toSelectors.addAll(toNode.getSelectors());
+ }
+
+ PlanNode nodeBelowSelects = null;
+
+ // Walk down the 'fromJoined' side looking for all SELECT nodes ...
+ for (PlanNode select : fromJoined.findAllAtOrBelow(Type.SELECT)) {
+ // If all of the SELECT's selectors are also found on the right ...
+ if (toSelectors.containsAll(select.getSelectors())) {
+ // Copy the criteria ...
+ PlanNode copy = new PlanNode(Type.SELECT, select.getSelectors());
+ copy.setProperty(Property.SELECT_CRITERIA, select.getProperty(Property.SELECT_CRITERIA));
+
+ if (nodeBelowSelects == null) {
+ nodeBelowSelects = toJoined.findAtOrBelow(Type.SOURCE, Type.JOIN, Type.SET_OPERATION, Type.NULL);
+ if (nodeBelowSelects == null) {
+ nodeBelowSelects = toJoined;
+ }
+ }
+ nodeBelowSelects.insertAsParent(copy);
+ nodeBelowSelects = copy;
+ }
+ }
+ }
+
protected PlanNode copySelectNode( QueryContext context,
PlanNode selectNode,
SelectorName selectorName,
Copied: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RaiseSelectCriteria.java (from rev 1299, trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/CopyCriteria.java)
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RaiseSelectCriteria.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RaiseSelectCriteria.java 2009-10-21 17:02:40 UTC (rev 1300)
@@ -0,0 +1,254 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.query.optimize;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.property.Name;
+import org.jboss.dna.graph.property.ValueFactory;
+import org.jboss.dna.graph.query.QueryContext;
+import org.jboss.dna.graph.query.model.Column;
+import org.jboss.dna.graph.query.model.Constraint;
+import org.jboss.dna.graph.query.model.EquiJoinCondition;
+import org.jboss.dna.graph.query.model.JoinCondition;
+import org.jboss.dna.graph.query.model.PropertyExistence;
+import org.jboss.dna.graph.query.model.PropertyValue;
+import org.jboss.dna.graph.query.model.SelectorName;
+import org.jboss.dna.graph.query.model.Visitable;
+import org.jboss.dna.graph.query.model.Visitors;
+import org.jboss.dna.graph.query.model.Visitors.AbstractVisitor;
+import org.jboss.dna.graph.query.plan.PlanNode;
+import org.jboss.dna.graph.query.plan.PlanUtil;
+import org.jboss.dna.graph.query.plan.PlanNode.Property;
+import org.jboss.dna.graph.query.plan.PlanNode.Type;
+
+/**
+ * An {@link OptimizerRule optimizer rule} that moves up higher in the plan any SELECT node that appears below a JOIN node and
+ * that applies to selectors that are on the other side of the join.
+ * <p>
+ * This step is often counterintuitive, since one of the best optimizations a query optimizer can do is to
+ * {@link PushSelectCriteria push down SELECT nodes} as far as they'll go. But consider the case of a SOURCE node that appears
+ * below a JOIN, where the SOURCE node is a view. The optimizer {@link ReplaceViews replaces the SOURCE node with the view
+ * definition}, and if the view definition includes a SELECT node, that SELECT node appears below the JOIN. Plus, that SELECT node
+ * is already pushed down as far as it can go (assuming the view isn't defined to use another view). However, the JOIN may use the
+ * same selector on the opposite side, and it may be possible that the same SELECT node may apply to the other side of the JOIN.
+ * In this case, we can push <i>up</i> the SELECT node higher than the JOIN, and then the push-down would cause the SELECT to be
+ * copied to both sides of the JOIN.
+ * </p>
+ * <p>
+ * Here is an example plan that involves a JOIN of two SOURCE nodes:
+ *
+ * <pre>
+ * ...
+ * |
+ * JOIN
+ * / \
+ * / SOURCE({@link Property#SOURCE_NAME SOURCE_NAME}="t1")
+ * /
+ * SOURCE({@link Property#SOURCE_NAME SOURCE_NAME}="v1")
+ * </pre>
+ *
+ * If the right-side SOURCE references the "t1" table, and the left-side SOURCE references a view "v1" defined as "
+ * <code>SELECT * FROM t1 WHERE t1.id < 3</code>", then the {@link ReplaceViews} rule would change this plan to be:
+ *
+ * <pre>
+ * ...
+ * |
+ * JOIN
+ * / \
+ * / SOURCE({@link Property#SOURCE_NAME SOURCE_NAME}="t1")
+ * /
+ * PROJECT
+ * |
+ * SELECT applies the "t1.id < 3" criteria
+ * |
+ * SOURCE({@link Property#SOURCE_NAME SOURCE_NAME}="t1")
+ * </pre>
+ *
+ * Again, the SELECT cannot be pushed down any further. But the whole query can be made more efficient - because the SELECT on the
+ * left-side of the JOIN will include only those tuples from 't1' that satisfy the SELECT, the JOIN will only include those tuples
+ * that also satisfy this criteria, even though more tuples are returned from the right-side SOURCE.
+ * </p>
+ * <p>
+ * In this case, the left-hand SELECT can actually be copied to the right-hand side of the JOIN, resulting in:
+ *
+ * <pre>
+ * ...
+ * |
+ * JOIN
+ * / \
+ * / SELECT applies the "t1.id < 3" criteria
+ * / |
+ * PROJECT SOURCE({@link Property#SOURCE_NAME SOURCE_NAME}="t1")
+ * |
+ * SELECT applies the "t1.id < 3" criteria
+ * |
+ * SOURCE({@link Property#SOURCE_NAME SOURCE_NAME}="t1")
+ * </pre>
+ *
+ * </p>
+ */
+@Immutable
+public class RaiseSelectCriteria implements OptimizerRule {
+
+ public static final RaiseSelectCriteria INSTANCE = new RaiseSelectCriteria();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.query.optimize.OptimizerRule#execute(org.jboss.dna.graph.query.QueryContext,
+ * org.jboss.dna.graph.query.plan.PlanNode, java.util.LinkedList)
+ */
+ public PlanNode execute( QueryContext context,
+ PlanNode plan,
+ LinkedList<OptimizerRule> ruleStack ) {
+ Set<PlanNode> copiedSelectNodes = new HashSet<PlanNode>();
+
+ for (PlanNode join : plan.findAllAtOrBelow(Type.JOIN)) {
+ // Get the join condition ...
+ JoinCondition joinCondition = join.getProperty(Property.JOIN_CONDITION, JoinCondition.class);
+ if (joinCondition instanceof EquiJoinCondition) {
+ EquiJoinCondition equiJoinCondition = (EquiJoinCondition)joinCondition;
+ SelectorName selector1 = equiJoinCondition.getSelector1Name();
+ SelectorName selector2 = equiJoinCondition.getSelector2Name();
+ Name property1 = equiJoinCondition.getProperty1Name();
+ Name property2 = equiJoinCondition.getProperty2Name();
+
+ // Walk up the tree looking for SELECT nodes that apply to one of the sides ...
+ PlanNode node = join.getParent();
+ while (node != null) {
+ if (!copiedSelectNodes.contains(node)) {
+ PlanNode copy = copySelectNode(context, node, selector1, property1, selector2, property2);
+ if (copy != null) {
+ node.insertAsParent(copy);
+ copiedSelectNodes.add(node);
+ copiedSelectNodes.add(copy);
+ } else {
+ copy = copySelectNode(context, node, selector2, property2, selector1, property1);
+ if (copy != null) {
+ node.insertAsParent(copy);
+ copiedSelectNodes.add(node);
+ copiedSelectNodes.add(copy);
+ }
+ }
+ }
+ node = node.getParent();
+ }
+ }
+ }
+ return plan;
+ }
+
+ protected PlanNode copySelectNode( QueryContext context,
+ PlanNode selectNode,
+ SelectorName selectorName,
+ Name propertyName,
+ SelectorName copySelectorName,
+ Name copyPropertyName ) {
+ if (selectNode.isNot(Type.SELECT)) return null;
+ if (selectNode.getSelectors().size() != 1 || !selectNode.getSelectors().contains(selectorName)) return null;
+
+ Constraint constraint = selectNode.getProperty(Property.SELECT_CRITERIA, Constraint.class);
+ Set<Column> columns = getColumnsReferencedBy(constraint, context.getExecutionContext());
+ if (columns.size() != 1) return null;
+ Column column = columns.iterator().next();
+ if (!column.getSelectorName().equals(selectorName)) return null;
+ if (!column.getPropertyName().equals(propertyName)) return null;
+
+ // We know that this constraint ONLY applies to the referenced selector and property,
+ // so we will duplicate this constraint ...
+
+ // Create the new node ...
+ PlanNode copy = new PlanNode(Type.SELECT, copySelectorName);
+
+ // Copy the constraint, but change the references to the copy selector and property ...
+ ValueFactory<String> stringFactory = context.getExecutionContext().getValueFactories().getStringFactory();
+ PlanUtil.ColumnMapping mappings = new PlanUtil.ColumnMapping(selectorName);
+ mappings.map(stringFactory.create(propertyName), new Column(copySelectorName, copyPropertyName,
+ stringFactory.create(copyPropertyName)));
+ Constraint newCriteria = PlanUtil.replaceReferences(context, constraint, mappings, copy);
+ copy.setProperty(Property.SELECT_CRITERIA, newCriteria);
+
+ return copy;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
+
+ /**
+ * Get the set of Column objects that represent those columns referenced by the visitable object.
+ *
+ * @param visitable the object to be visited
+ * @param context the context; may not be null
+ * @return the set of Column objects, with column names that always are the string-form of the
+ * {@link Column#getPropertyName() property name}; never null
+ */
+ public static Set<Column> getColumnsReferencedBy( Visitable visitable,
+ ExecutionContext context ) {
+ if (visitable == null) return Collections.emptySet();
+ final ValueFactory<String> stringFactory = context.getValueFactories().getStringFactory();
+ final Set<Column> symbols = new HashSet<Column>();
+ // Walk the entire structure, so only supply a StrategyVisitor (that does no navigation) ...
+ Visitors.visitAll(visitable, new AbstractVisitor() {
+ protected void addColumnFor( SelectorName selectorName,
+ Name property ) {
+ symbols.add(new Column(selectorName, property, stringFactory.create(property)));
+ }
+
+ @Override
+ public void visit( Column column ) {
+ symbols.add(column);
+ }
+
+ @Override
+ public void visit( EquiJoinCondition joinCondition ) {
+ addColumnFor(joinCondition.getSelector1Name(), joinCondition.getProperty1Name());
+ addColumnFor(joinCondition.getSelector2Name(), joinCondition.getProperty2Name());
+ }
+
+ @Override
+ public void visit( PropertyExistence prop ) {
+ addColumnFor(prop.getSelectorName(), prop.getPropertyName());
+ }
+
+ @Override
+ public void visit( PropertyValue prop ) {
+ addColumnFor(prop.getSelectorName(), prop.getPropertyName());
+ }
+ });
+ return symbols;
+ }
+
+}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/ReplaceViews.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/ReplaceViews.java 2009-10-21 17:02:10 UTC (rev 1299)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/ReplaceViews.java 2009-10-21 17:02:40 UTC (rev 1300)
@@ -43,6 +43,32 @@
/**
* An {@link OptimizerRule optimizer rule} that replaces any SOURCE nodes that happen to be {@link View views}. This rewriting
* changes all of the elements of the plan that reference the SOURCE and it's columns, including criteria, project nodes, etc.
+ * <p>
+ * For example, here is the portion of a plan that uses a single SOURCE that is defined to use a view.
+ *
+ * <pre>
+ * ...
+ * |
+ * SOURCE1
+ * </pre>
+ *
+ * This same SOURCE node is then replaced with the view's definition:
+ *
+ * <pre>
+ * ...
+ * |
+ * PROJECT with the list of columns being SELECTed
+ * |
+ * SELECT1
+ * | One or more SELECT plan nodes that each have
+ * SELECT2 a single non-join constraint that are then all AND-ed
+ * | together
+ * SELECTn
+ * |
+ * SOURCE
+ * </pre>
+ *
+ * </p>
*/
@Immutable
public class ReplaceViews implements OptimizerRule {
@@ -113,6 +139,12 @@
} while (foundViews);
if (foundViews) {
+ // We'll need to try to push up criteria from the join, but we only should do this after this rule
+ // is completely done ...
+ if (!(ruleStack.getFirst() instanceof RaiseSelectCriteria)) {
+ ruleStack.addFirst(RaiseSelectCriteria.INSTANCE);
+ }
+
// We re-wrote at least one SOURCE, but the resulting plan tree for the view could actually reference
// other views. Therefore, re-run this rule ...
ruleStack.addFirst(this);
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanNode.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanNode.java 2009-10-21 17:02:10 UTC (rev 1299)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanNode.java 2009-10-21 17:02:40 UTC (rev 1300)
@@ -1090,6 +1090,40 @@
}
/**
+ * Find all of the nodes that are at or below this node.
+ *
+ * @return the collection of nodes that are at or below this node; never null and never empty
+ */
+ public List<PlanNode> findAllAtOrBelow() {
+ return findAllAtOrBelow(Traversal.PRE_ORDER);
+ }
+
+ /**
+ * Find all of the nodes that are at or below this node.
+ *
+ * @param order the order to traverse; may not be null
+ * @return the collection of nodes that are at or below this node; never null and never empty
+ */
+ public List<PlanNode> findAllAtOrBelow( Traversal order ) {
+ assert order != null;
+ List<PlanNode> results = new LinkedList<PlanNode>();
+ LinkedList<PlanNode> queue = new LinkedList<PlanNode>();
+ queue.add(this);
+ while (!queue.isEmpty()) {
+ PlanNode aNode = queue.poll();
+ switch (order) {
+ case LEVEL_ORDER:
+ queue.addAll(aNode.getChildren());
+ break;
+ case PRE_ORDER:
+ queue.addAll(0, aNode.getChildren());
+ break;
+ }
+ }
+ return results;
+ }
+
+ /**
* Find all of the nodes of the specified type that are at or below this node.
*
* @param typeToFind the type of node to find; may not be null
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/process/QueryProcessor.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/process/QueryProcessor.java 2009-10-21 17:02:10 UTC (rev 1299)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/process/QueryProcessor.java 2009-10-21 17:02:40 UTC (rev 1300)
@@ -113,6 +113,15 @@
return null;
}
+ /**
+ * Create the {@link ProcessingComponent} that processes a single {@link Type#ACCESS} branch of a query plan.
+ *
+ * @param context the context in which query is being evaluated; never null
+ * @param accessNode the node in the query plan that represents the {@link Type#ACCESS} plan; never null
+ * @param resultColumns the columns that are to be returned; never null
+ * @param analyzer the criteria analyzer; never null
+ * @return the processing component; may not be null
+ */
protected abstract ProcessingComponent createAccessComponent( QueryContext context,
PlanNode accessNode,
Columns resultColumns,
@@ -141,10 +150,11 @@
ProcessingComponent component = null;
switch (node.getType()) {
case ACCESS:
- // Create the component under the ACCESS ...
+ // Create the component to handle the ACCESS node ...
assert node.getChildCount() == 1;
- // Don't do anything special with an access node at the moment ...
- component = createComponent(context, node.getFirstChild(), columns, analyzer);
+ component = createAccessComponent(context, node, columns, analyzer);
+ // // Don't do anything special with an access node at the moment ...
+ // component = createComponent(context, node.getFirstChild(), columns, analyzer);
break;
case DUP_REMOVE:
// Create the component under the DUP_REMOVE ...
16 years, 2 months
DNA SVN: r1299 - in trunk/dna-graph/src: test/java/org/jboss/dna/graph/query/optimize and 1 other directory.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-10-21 13:02:10 -0400 (Wed, 21 Oct 2009)
New Revision: 1299
Removed:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizerTest.java
Log:
DNA-467 Removed optimization rule that combined set criteria (e.g., 'IN (1,2,3)'), since it was AND-ing together OR-ed criteria and was thus invalid.
Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java 2009-10-21 17:01:35 UTC (rev 1298)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java 2009-10-21 17:02:10 UTC (rev 1299)
@@ -1,113 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.graph.query.optimize;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.graph.query.QueryContext;
-import org.jboss.dna.graph.query.model.Constraint;
-import org.jboss.dna.graph.query.model.SetCriteria;
-import org.jboss.dna.graph.query.plan.PlanNode;
-import org.jboss.dna.graph.query.plan.PlanNode.Property;
-import org.jboss.dna.graph.query.plan.PlanNode.Type;
-
-/**
- * An {@link OptimizerRule optimizer rule} that merges SELECT nodes that have {@link SetCriteria} applied to the same column on
- * the same selector.
- *
- * @param <SimilarityType> the type used to compare and identify similar nodes
- * @param <ConstraintType> the concrete type of Constraint objects that are being merged
- */
-@Immutable
-public abstract class AbstractMergeSelectNodes<SimilarityType, ConstraintType extends Constraint> implements OptimizerRule {
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.query.optimize.OptimizerRule#execute(org.jboss.dna.graph.query.QueryContext,
- * org.jboss.dna.graph.query.plan.PlanNode, java.util.LinkedList)
- */
- @SuppressWarnings( "unchecked" )
- public PlanNode execute( QueryContext context,
- PlanNode plan,
- LinkedList<OptimizerRule> ruleStack ) {
- Map<SimilarityType, LinkedList<PlanNode>> mergeables = new HashMap<SimilarityType, LinkedList<PlanNode>>();
- for (PlanNode source : plan.findAllAtOrBelow(Type.SOURCE)) {
- // Walk up from the SOURCE and look for all SELECT nodes ...
- PlanNode node = source.getParent();
- while (node != null && node.is(Type.SELECT)) {
- Constraint constraint = node.getProperty(Property.SELECT_CRITERIA, Constraint.class);
- SimilarityType operand = getSimilarityKey(constraint);
- if (operand != null) {
- LinkedList<PlanNode> nodes = mergeables.get(operand);
- if (nodes == null) {
- nodes = new LinkedList<PlanNode>();
- mergeables.put(operand, nodes);
- }
- nodes.addFirst(node); // So that the list is in the downward order they appear in the plan
- }
- node = node.getParent();
- }
-
- // Merge all mergeable SELECT nodes ...
- for (LinkedList<PlanNode> mergeable : mergeables.values()) {
- if (mergeable.size() > 1) {
- Iterator<PlanNode> iter = mergeable.iterator();
- PlanNode firstSelect = iter.next();
- Constraint constraint = firstSelect.getProperty(Property.SELECT_CRITERIA, Constraint.class);
- while (iter.hasNext()) {
- PlanNode nextSelect = iter.next();
- Constraint nextConstraint = nextSelect.getProperty(Property.SELECT_CRITERIA, Constraint.class);
- constraint = merge((ConstraintType)constraint, (ConstraintType)nextConstraint);
- nextSelect.extractFromParent();
- }
- firstSelect.setProperty(Property.SELECT_CRITERIA, constraint);
- }
- }
- mergeables.clear();
- }
- return plan;
- }
-
- /**
- * Obtain the similarity key that will be used to determine whether two SELECT nodes should be merged.
- *
- * @param constraint the constraint from the SELECT node
- * @return the similarity key, or null if the constraint should not be merged
- */
- protected abstract SimilarityType getSimilarityKey( Constraint constraint );
-
- /**
- * Merge the two constraints.
- *
- * @param firstConstraint the first constraint
- * @param secondConstraint the second constraint
- * @return the merged constraint
- */
- protected abstract Constraint merge( ConstraintType firstConstraint,
- ConstraintType secondConstraint );
-}
Deleted: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java 2009-10-21 17:01:35 UTC (rev 1298)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java 2009-10-21 17:02:10 UTC (rev 1299)
@@ -1,89 +0,0 @@
-/*
- * JBoss DNA (http://www.jboss.org/dna)
- * See the COPYRIGHT.txt file distributed with this work for information
- * regarding copyright ownership. Some portions may be licensed
- * to Red Hat, Inc. under one or more contributor license agreements.
- * See the AUTHORS.txt file in the distribution for a full listing of
- * individual contributors.
- *
- * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
- * is licensed to you under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * JBoss DNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.dna.graph.query.optimize;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import net.jcip.annotations.Immutable;
-import org.jboss.dna.graph.query.model.Constraint;
-import org.jboss.dna.graph.query.model.DynamicOperand;
-import org.jboss.dna.graph.query.model.SetCriteria;
-import org.jboss.dna.graph.query.model.StaticOperand;
-
-/**
- * An {@link OptimizerRule optimizer rule} that merges SELECT nodes that have {@link SetCriteria} applied to the same column on
- * the same selector.
- */
-@Immutable
-public class MergeSetCriteria extends AbstractMergeSelectNodes<DynamicOperand, SetCriteria> {
-
- public static final MergeSetCriteria INSTANCE = new MergeSetCriteria();
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.query.optimize.AbstractMergeSelectNodes#getSimilarityKey(org.jboss.dna.graph.query.model.Constraint)
- */
- @Override
- protected DynamicOperand getSimilarityKey( Constraint constraint ) {
- if (constraint instanceof SetCriteria) {
- // Look for the list of plan nodes for this operand ...
- return ((SetCriteria)constraint).getLeftOperand();
- }
- return null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.query.optimize.AbstractMergeSelectNodes#merge(org.jboss.dna.graph.query.model.Constraint,
- * org.jboss.dna.graph.query.model.Constraint)
- */
- @Override
- protected Constraint merge( SetCriteria firstConstraint,
- SetCriteria secondConstraint ) {
- assert firstConstraint.getLeftOperand().equals(secondConstraint.getLeftOperand());
- Set<StaticOperand> allOperands = new HashSet<StaticOperand>();
- List<StaticOperand> orderedOperands = new ArrayList<StaticOperand>(firstConstraint.getRightOperands());
- allOperands.addAll(firstConstraint.getRightOperands());
- for (StaticOperand second : secondConstraint.getRightOperands()) {
- if (allOperands.add(second)) {
- orderedOperands.add(second);
- }
- }
- return new SetCriteria(firstConstraint.getLeftOperand(), orderedOperands);
- }
-
- /**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return getClass().getSimpleName();
- }
-}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java 2009-10-21 17:01:35 UTC (rev 1298)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java 2009-10-21 17:02:10 UTC (rev 1299)
@@ -69,7 +69,6 @@
*/
protected void populateRuleStack( LinkedList<OptimizerRule> ruleStack,
PlanHints hints ) {
- ruleStack.addFirst(MergeSetCriteria.INSTANCE);
if (hints.hasJoin) {
ruleStack.addFirst(ChooseJoinAlgorithm.USE_ONLY_NESTED_JOIN_ALGORITHM);
ruleStack.addFirst(RewriteIdentityJoins.INSTANCE);
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizerTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizerTest.java 2009-10-21 17:01:35 UTC (rev 1298)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizerTest.java 2009-10-21 17:02:10 UTC (rev 1299)
@@ -332,11 +332,17 @@
select1.setProperty(Property.SELECT_CRITERIA, new FullTextSearch(selector("all"), name("a2"), "something"));
PlanNode select2 = new PlanNode(Type.SELECT, select1, selector("all"));
select2.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("primaryType")),
- new Literal("t1"), new Literal("t0"), new Literal("t2")));
+ new Literal("t1"), new Literal("t0")));
PlanNode select3 = new PlanNode(Type.SELECT, select2, selector("all"));
select3.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("mixins")),
- new Literal("t3"), new Literal("t4"), new Literal("t5")));
- PlanNode source = new PlanNode(Type.SOURCE, select3, selector("all"));
+ new Literal("t3"), new Literal("t4")));
+ PlanNode select4 = new PlanNode(Type.SELECT, select3, selector("all"));
+ select4.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("primaryType")),
+ new Literal("t2"), new Literal("t0")));
+ PlanNode select5 = new PlanNode(Type.SELECT, select4, selector("all"));
+ select5.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("mixins")),
+ new Literal("t4"), new Literal("t5")));
+ PlanNode source = new PlanNode(Type.SOURCE, select5, selector("all"));
source.setProperty(Property.SOURCE_NAME, selector("all"));
source.setProperty(Property.SOURCE_COLUMNS, context.getSchemata().getTable(selector("all")).getColumns());
@@ -410,11 +416,17 @@
select1.setProperty(Property.SELECT_CRITERIA, new FullTextSearch(selector("all"), name("a2"), "something"));
PlanNode select2 = new PlanNode(Type.SELECT, select1, selector("all"));
select2.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("primaryType")),
- new Literal("t1"), new Literal("t0"), new Literal("t2")));
+ new Literal("t1"), new Literal("t0")));
PlanNode select3 = new PlanNode(Type.SELECT, select2, selector("all"));
select3.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("mixins")),
- new Literal("t3"), new Literal("t4"), new Literal("t5")));
- PlanNode source = new PlanNode(Type.SOURCE, select3, selector("all"));
+ new Literal("t3"), new Literal("t4")));
+ PlanNode select4 = new PlanNode(Type.SELECT, select3, selector("all"));
+ select4.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("primaryType")),
+ new Literal("t2"), new Literal("t0")));
+ PlanNode select5 = new PlanNode(Type.SELECT, select4, selector("all"));
+ select5.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("mixins")),
+ new Literal("t4"), new Literal("t5")));
+ PlanNode source = new PlanNode(Type.SOURCE, select5, selector("all"));
source.setProperty(Property.SOURCE_NAME, selector("all"));
source.setProperty(Property.SOURCE_COLUMNS, context.getSchemata().getTable(selector("all")).getColumns());
16 years, 2 months
DNA SVN: r1298 - in trunk: dna-graph/src/main/java/org/jboss/dna/graph/query/optimize and 4 other directories.
by dna-commits@lists.jboss.org
Author: rhauch
Date: 2009-10-21 13:01:35 -0400 (Wed, 21 Oct 2009)
New Revision: 1298
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/AllNodes.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/And.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/BindVariableName.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/ChildNode.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/ChildNodeJoinCondition.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Column.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Comparison.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/DescendantNode.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/DescendantNodeJoinCondition.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/EquiJoinCondition.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/FullTextSearch.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/FullTextSearchScore.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Join.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Length.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Limit.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Literal.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/LowerCase.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NamedSelector.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeDepth.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeLocalName.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeName.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodePath.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Not.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Or.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Ordering.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/PropertyExistence.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/PropertyValue.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Query.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SameNode.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SameNodeJoinCondition.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Selector.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SetCriteria.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SetQuery.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/UpperCase.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/PushProjects.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/PushSelectCriteria.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/ReplaceViews.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RewriteIdentityJoins.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/CanonicalPlanner.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanNode.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanUtil.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/validate/ImmutableSchemata.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/ReplaceViewsTest.java
trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizerTest.java
trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/xpath/XPathToQueryTranslatorTest.java
Log:
DNA-467 Added another optimization rule to merge set criteria, and added hashCode() methods to all of the AQM classes.
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/AllNodes.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/AllNodes.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/AllNodes.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -60,6 +60,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getName().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/And.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/And.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/And.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
/**
* A constraint that evaluates to true when <i>both</i> of the other constraints evaluate to true.
@@ -34,6 +35,7 @@
private final Constraint left;
private final Constraint right;
+ private final int hc;
public And( Constraint left,
Constraint right ) {
@@ -41,6 +43,7 @@
CheckArg.isNotNull(right, "right");
this.left = left;
this.right = right;
+ this.hc = HashCode.compute(this.left, this.right);
}
/**
@@ -70,6 +73,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -77,6 +90,7 @@
if (obj == this) return true;
if (obj instanceof And) {
And that = (And)obj;
+ if (this.hc != that.hc) return false;
return left.equals(that.left) && right.equals(that.right);
}
return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/BindVariableName.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/BindVariableName.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/BindVariableName.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -59,6 +59,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return variableName.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/ChildNode.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/ChildNode.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/ChildNode.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.graph.property.Path;
/**
@@ -34,6 +35,7 @@
public class ChildNode extends Constraint {
private final SelectorName selectorName;
private final Path parentPath;
+ private final int hc;
/**
* Create a constraint requiring that the node identified by the selector is a child of the node reachable by the supplied
@@ -48,6 +50,7 @@
CheckArg.isNotNull(parentPath, "parentPath");
this.selectorName = selectorName;
this.parentPath = parentPath;
+ this.hc = HashCode.compute(this.selectorName, this.parentPath);
}
/**
@@ -77,6 +80,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -84,6 +97,7 @@
if (obj == this) return true;
if (obj instanceof ChildNode) {
ChildNode that = (ChildNode)obj;
+ if (this.hc != that.hc) return false;
if (!this.selectorName.equals(that.selectorName)) return false;
if (!this.parentPath.equals(that.parentPath)) return false;
return true;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/ChildNodeJoinCondition.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/ChildNodeJoinCondition.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/ChildNodeJoinCondition.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
/**
* A join condition that evaluates to true only when the named child node is indeed a child of the named parent node.
@@ -33,6 +34,7 @@
public class ChildNodeJoinCondition extends JoinCondition {
private final SelectorName childSelectorName;
private final SelectorName parentSelectorName;
+ private final int hc;
/**
* Create a join condition that determines whether the node identified by the child selector is a child of the node identified
@@ -47,6 +49,7 @@
CheckArg.isNotNull(parentSelectorName, "parentSelectorName");
this.childSelectorName = childSelectorName;
this.parentSelectorName = parentSelectorName;
+ this.hc = HashCode.compute(this.childSelectorName, this.parentSelectorName);
}
/**
@@ -76,6 +79,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -83,6 +96,7 @@
if (obj == this) return true;
if (obj instanceof ChildNodeJoinCondition) {
ChildNodeJoinCondition that = (ChildNodeJoinCondition)obj;
+ if (this.hc != that.hc) return false;
if (!this.childSelectorName.equals(that.childSelectorName)) return false;
if (!this.parentSelectorName.equals(that.parentSelectorName)) return false;
return true;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Column.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Column.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Column.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -102,6 +102,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getSelectorName().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Comparison.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Comparison.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Comparison.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
/**
* A constraint that evaluates to true when the defined operation evaluates to true.
@@ -35,6 +36,7 @@
private final DynamicOperand operand1;
private final StaticOperand operand2;
private final Operator operator;
+ private final int hc;
public Comparison( DynamicOperand operand1,
Operator operator,
@@ -45,6 +47,7 @@
this.operand1 = operand1;
this.operand2 = operand2;
this.operator = operator;
+ this.hc = HashCode.compute(this.operand1, this.operand2, this.operator);
}
/**
@@ -81,6 +84,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -88,6 +101,7 @@
if (obj == this) return true;
if (obj instanceof Comparison) {
Comparison that = (Comparison)obj;
+ if (this.hc != that.hc) return false;
if (!this.operator.equals(that.operator)) return false;
if (!this.operand1.equals(that.operand1)) return false;
if (!this.operand2.equals(that.operand2)) return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/DescendantNode.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/DescendantNode.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/DescendantNode.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -77,6 +77,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getSelectorName().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/DescendantNodeJoinCondition.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/DescendantNodeJoinCondition.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/DescendantNodeJoinCondition.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
/**
* A join condition that evaluates to true only when the named node is a descendant of another named node.
@@ -33,6 +34,7 @@
public class DescendantNodeJoinCondition extends JoinCondition {
private final SelectorName descendantSelectorName;
private final SelectorName ancestorSelectorName;
+ private final int hc;
/**
* Create a join condition that determines whether the node identified by the descendant selector is indeed a descendant of
@@ -47,6 +49,7 @@
CheckArg.isNotNull(ancestorSelectorName, "ancestorSelectorName");
this.descendantSelectorName = descendantSelectorName;
this.ancestorSelectorName = ancestorSelectorName;
+ this.hc = HashCode.compute(this.descendantSelectorName, this.ancestorSelectorName);
}
/**
@@ -76,6 +79,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -83,6 +96,7 @@
if (obj == this) return true;
if (obj instanceof DescendantNodeJoinCondition) {
DescendantNodeJoinCondition that = (DescendantNodeJoinCondition)obj;
+ if (this.hc != that.hc) return false;
if (!this.descendantSelectorName.equals(that.descendantSelectorName)) return false;
if (!this.ancestorSelectorName.equals(that.ancestorSelectorName)) return false;
return true;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/EquiJoinCondition.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/EquiJoinCondition.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/EquiJoinCondition.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.graph.property.Name;
/**
@@ -42,6 +43,7 @@
private final Name property1Name;
private final SelectorName selector2Name;
private final Name property2Name;
+ private final int hc;
public EquiJoinCondition( SelectorName selector1Name,
Name property1Name,
@@ -55,6 +57,7 @@
this.property1Name = property1Name;
this.selector2Name = selector2Name;
this.property2Name = property2Name;
+ this.hc = HashCode.compute(this.selector1Name, this.property1Name, this.selector2Name, this.property2Name);
}
public EquiJoinCondition( Column column1,
@@ -103,6 +106,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -110,6 +123,7 @@
if (obj == this) return true;
if (obj instanceof EquiJoinCondition) {
EquiJoinCondition that = (EquiJoinCondition)obj;
+ if (this.hc != that.hc) return false;
if (!this.selector1Name.equals(that.selector1Name)) return false;
if (!this.selector2Name.equals(that.selector2Name)) return false;
if (!this.property1Name.equals(that.property1Name)) return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/FullTextSearch.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/FullTextSearch.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/FullTextSearch.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -28,6 +28,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.text.ParsingException;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.common.util.ObjectUtil;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.query.parse.FullTextSearchParser;
@@ -42,6 +43,7 @@
private final Name propertyName;
private final String fullTextSearchExpression;
private Term term;
+ private final int hc;
/**
* Create a constraint defining a full-text search against the property values on node within the search scope.
@@ -60,6 +62,7 @@
this.selectorName = selectorName;
this.propertyName = propertyName;
this.fullTextSearchExpression = fullTextSearchExpression;
+ this.hc = HashCode.compute(this.selectorName, this.propertyName, this.fullTextSearchExpression);
}
/**
@@ -78,6 +81,7 @@
this.propertyName = propertyName;
this.fullTextSearchExpression = fullTextSearchExpression;
this.term = null;
+ this.hc = HashCode.compute(this.selectorName, this.propertyName, this.fullTextSearchExpression);
}
/**
@@ -93,6 +97,7 @@
this.selectorName = selectorName;
this.propertyName = null;
this.fullTextSearchExpression = fullTextSearchExpression;
+ this.hc = HashCode.compute(this.selectorName, this.propertyName, this.fullTextSearchExpression);
}
/**
@@ -143,6 +148,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -150,6 +165,7 @@
if (obj == this) return true;
if (obj instanceof FullTextSearch) {
FullTextSearch that = (FullTextSearch)obj;
+ if (this.hc != that.hc) return false;
if (!this.selectorName.equals(that.selectorName)) return false;
if (!ObjectUtil.isEqualWithNulls(this.propertyName, that.propertyName)) return false;
if (!this.fullTextSearchExpression.equals(that.fullTextSearchExpression)) return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/FullTextSearchScore.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/FullTextSearchScore.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/FullTextSearchScore.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -67,6 +67,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getSelectorName().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Join.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Join.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Join.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
/**
*
@@ -36,6 +37,7 @@
private final Source right;
private final JoinType type;
private final JoinCondition joinCondition;
+ private final int hc;
/**
* Create a join of the left and right sources, using the supplied join condition. The outputs of the left and right sources
@@ -58,6 +60,7 @@
this.right = right;
this.type = type;
this.joinCondition = joinCondition;
+ this.hc = HashCode.compute(this.left, this.right, this.type, this.joinCondition);
}
/**
@@ -101,6 +104,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -108,6 +121,7 @@
if (obj == this) return true;
if (obj instanceof Join) {
Join that = (Join)obj;
+ if (this.hc != that.hc) return false;
if (!this.type.equals(that.type)) return false;
if (!this.left.equals(that.left)) return false;
if (!this.right.equals(that.right)) return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Length.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Length.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Length.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -73,6 +73,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getPropertyValue().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Limit.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Limit.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Limit.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -107,6 +107,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return rowLimit;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Literal.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Literal.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Literal.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -59,6 +59,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getValue().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/LowerCase.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/LowerCase.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/LowerCase.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -74,6 +74,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return operand.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NamedSelector.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NamedSelector.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NamedSelector.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -67,6 +67,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getName().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeDepth.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeDepth.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeDepth.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -67,6 +67,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getSelectorName().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeLocalName.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeLocalName.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeLocalName.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -66,6 +66,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getSelectorName().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeName.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeName.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodeName.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -66,6 +66,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getSelectorName().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodePath.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodePath.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/NodePath.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -67,6 +67,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getSelectorName().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Not.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Not.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Not.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -67,6 +67,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getConstraint().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Or.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Or.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Or.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
/**
* A constraint that evaluates to true when either of the other constraints evaluates to true.
@@ -34,6 +35,7 @@
private final Constraint left;
private final Constraint right;
+ private final int hc;
/**
* Create a constraint that evaluates to true if either of the two supplied constraints evaluates to true.
@@ -48,6 +50,7 @@
CheckArg.isNotNull(right, "right");
this.left = left;
this.right = right;
+ this.hc = HashCode.compute(this.left, this.right);
}
/**
@@ -81,6 +84,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -88,6 +101,7 @@
if (obj == this) return true;
if (obj instanceof Or) {
Or that = (Or)obj;
+ if (this.hc != that.hc) return false;
return this.left.equals(that.left) && this.right.equals(that.right);
}
return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Ordering.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Ordering.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Ordering.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -81,6 +81,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return operand.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/PropertyExistence.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/PropertyExistence.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/PropertyExistence.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.graph.property.Name;
/**
@@ -34,6 +35,7 @@
public class PropertyExistence extends Constraint {
private final SelectorName selectorName;
private final Name propertyName;
+ private final int hc;
/**
* Create a constraint requiring that a property exist on a node.
@@ -47,6 +49,7 @@
CheckArg.isNotNull(propertyName, "propertyName");
this.selectorName = selectorName;
this.propertyName = propertyName;
+ this.hc = HashCode.compute(this.selectorName, this.propertyName);
}
/**
@@ -80,6 +83,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -87,6 +100,7 @@
if (obj == this) return true;
if (obj instanceof PropertyExistence) {
PropertyExistence that = (PropertyExistence)obj;
+ if (this.hc != that.hc) return false;
return this.selectorName.equals(that.selectorName) && this.propertyName.equals(that.propertyName);
}
return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/PropertyValue.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/PropertyValue.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/PropertyValue.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.graph.property.Name;
/**
@@ -34,6 +35,7 @@
public class PropertyValue extends DynamicOperand {
private final SelectorName selectorName;
private final Name propertyName;
+ private final int hc;
/**
* Create a dynamic operand that evaluates to the property values of the node identified by the selector.
@@ -48,6 +50,7 @@
CheckArg.isNotNull(propertyName, "propertyName");
this.selectorName = selectorName;
this.propertyName = propertyName;
+ this.hc = HashCode.compute(this.selectorName, this.propertyName);
}
/**
@@ -82,6 +85,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -89,6 +102,7 @@
if (obj == this) return true;
if (obj instanceof PropertyValue) {
PropertyValue that = (PropertyValue)obj;
+ if (this.hc != that.hc) return false;
return this.selectorName.equals(that.selectorName) && this.propertyName.equals(that.propertyName);
}
return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Query.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Query.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Query.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -29,6 +29,7 @@
import java.util.List;
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.common.util.ObjectUtil;
/**
@@ -43,6 +44,7 @@
private final Constraint constraint;
private final List<Column> columns;
private final boolean distinct;
+ private final int hc;
/**
* Create a new query that uses the supplied source.
@@ -57,6 +59,7 @@
this.constraint = null;
this.columns = Collections.<Column>emptyList();
this.distinct = IS_DISTINCT_DEFAULT;
+ this.hc = HashCode.compute(this.source, this.constraint, this.columns, this.distinct);
}
/**
@@ -84,6 +87,7 @@
this.constraint = constraint;
this.columns = columns != null ? columns : Collections.<Column>emptyList();
this.distinct = isDistinct;
+ this.hc = HashCode.compute(this.source, this.constraint, this.columns, this.distinct);
}
/**
@@ -189,6 +193,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -196,6 +210,7 @@
if (obj == this) return true;
if (obj instanceof Query) {
Query that = (Query)obj;
+ if (this.hc != that.hc) return false;
if (this.distinct != that.distinct) return false;
if (!this.source.equals(that.source)) return false;
if (!ObjectUtil.isEqualWithNulls(this.getLimits(), that.getLimits())) return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SameNode.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SameNode.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SameNode.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.graph.property.Path;
/**
@@ -34,6 +35,7 @@
public class SameNode extends Constraint {
private final SelectorName selectorName;
private final Path path;
+ private final int hc;
/**
* Create a constraint requiring that the node identified by the selector is reachable by the supplied absolute path.
@@ -48,6 +50,7 @@
CheckArg.isNotNull(path, "path");
this.selectorName = selectorName;
this.path = path;
+ this.hc = HashCode.compute(this.selectorName, this.path);
}
/**
@@ -81,6 +84,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -88,6 +101,7 @@
if (obj == this) return true;
if (obj instanceof SameNode) {
SameNode that = (SameNode)obj;
+ if (this.hc != that.hc) return false;
if (!this.selectorName.equals(that.selectorName)) return false;
if (!this.path.equals(that.path)) return false;
return true;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SameNodeJoinCondition.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SameNodeJoinCondition.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SameNodeJoinCondition.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,6 +25,7 @@
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.common.util.ObjectUtil;
import org.jboss.dna.graph.property.Path;
@@ -37,6 +38,7 @@
private final SelectorName selector1Name;
private final SelectorName selector2Name;
private final Path selector2Path;
+ private final int hc;
/**
* Create a join condition that determines whether the node identified by the first selector is the same as the node at the
@@ -56,6 +58,7 @@
this.selector1Name = selector1Name;
this.selector2Name = selector2Name;
this.selector2Path = selector2Path;
+ this.hc = HashCode.compute(this.selector1Name, this.selector2Name, this.selector2Path);
}
/**
@@ -73,6 +76,7 @@
this.selector1Name = selector1Name;
this.selector2Name = selector2Name;
this.selector2Path = null;
+ this.hc = HashCode.compute(this.selector1Name, this.selector2Name, this.selector2Path);
}
/**
@@ -115,6 +119,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -122,6 +136,7 @@
if (obj == this) return true;
if (obj instanceof SameNodeJoinCondition) {
SameNodeJoinCondition that = (SameNodeJoinCondition)obj;
+ if (this.hc != that.hc) return false;
if (!this.selector1Name.equals(that.selector1Name)) return false;
if (!this.selector2Name.equals(that.selector2Name)) return false;
if (!ObjectUtil.isEqualWithNulls(this.selector2Path, that.selector2Path)) return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Selector.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Selector.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/Selector.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -96,5 +96,4 @@
public boolean hasAlias() {
return alias != null;
}
-
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SetCriteria.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SetCriteria.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SetCriteria.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -23,7 +23,9 @@
*/
package org.jboss.dna.graph.query.model;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
@@ -44,6 +46,14 @@
this.setOperands = setOperands;
}
+ public SetCriteria( DynamicOperand left,
+ StaticOperand... setOperands ) {
+ CheckArg.isNotNull(left, "left");
+ CheckArg.isNotNull(setOperands, "setOperands");
+ this.left = left;
+ this.setOperands = Collections.unmodifiableList(Arrays.asList(setOperands));
+ }
+
/**
* @return operand1
*/
@@ -71,6 +81,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return left.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SetQuery.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SetQuery.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/SetQuery.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -31,6 +31,7 @@
import java.util.Map;
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
import org.jboss.dna.common.util.ObjectUtil;
import org.jboss.dna.graph.ExecutionContext;
@@ -101,6 +102,7 @@
private final QueryCommand right;
private final Operation operation;
private final boolean all;
+ private final int hc;
public SetQuery( QueryCommand left,
Operation operation,
@@ -114,6 +116,7 @@
this.right = right;
this.operation = operation;
this.all = all;
+ this.hc = HashCode.compute(this.left, this.right, this.operation);
}
public SetQuery( QueryCommand left,
@@ -130,6 +133,7 @@
this.right = right;
this.operation = operation;
this.all = all;
+ this.hc = HashCode.compute(this.left, this.right, this.operation);
}
/**
@@ -181,6 +185,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
@@ -188,6 +202,7 @@
if (obj == this) return true;
if (obj instanceof SetQuery) {
SetQuery that = (SetQuery)obj;
+ if (this.hc != that.hc) return false;
if (this.operation != that.operation) return false;
if (!this.left.equals(that.left)) return false;
if (!this.right.equals(that.right)) return false;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/UpperCase.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/UpperCase.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/model/UpperCase.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -76,6 +76,16 @@
/**
* {@inheritDoc}
*
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getOperand().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -0,0 +1,113 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.query.optimize;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.query.QueryContext;
+import org.jboss.dna.graph.query.model.Constraint;
+import org.jboss.dna.graph.query.model.SetCriteria;
+import org.jboss.dna.graph.query.plan.PlanNode;
+import org.jboss.dna.graph.query.plan.PlanNode.Property;
+import org.jboss.dna.graph.query.plan.PlanNode.Type;
+
+/**
+ * An {@link OptimizerRule optimizer rule} that merges SELECT nodes that have {@link SetCriteria} applied to the same column on
+ * the same selector.
+ *
+ * @param <SimilarityType> the type used to compare and identify similar nodes
+ * @param <ConstraintType> the concrete type of Constraint objects that are being merged
+ */
+@Immutable
+public abstract class AbstractMergeSelectNodes<SimilarityType, ConstraintType extends Constraint> implements OptimizerRule {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.query.optimize.OptimizerRule#execute(org.jboss.dna.graph.query.QueryContext,
+ * org.jboss.dna.graph.query.plan.PlanNode, java.util.LinkedList)
+ */
+ @SuppressWarnings( "unchecked" )
+ public PlanNode execute( QueryContext context,
+ PlanNode plan,
+ LinkedList<OptimizerRule> ruleStack ) {
+ Map<SimilarityType, LinkedList<PlanNode>> mergeables = new HashMap<SimilarityType, LinkedList<PlanNode>>();
+ for (PlanNode source : plan.findAllAtOrBelow(Type.SOURCE)) {
+ // Walk up from the SOURCE and look for all SELECT nodes ...
+ PlanNode node = source.getParent();
+ while (node != null && node.is(Type.SELECT)) {
+ Constraint constraint = node.getProperty(Property.SELECT_CRITERIA, Constraint.class);
+ SimilarityType operand = getSimilarityKey(constraint);
+ if (operand != null) {
+ LinkedList<PlanNode> nodes = mergeables.get(operand);
+ if (nodes == null) {
+ nodes = new LinkedList<PlanNode>();
+ mergeables.put(operand, nodes);
+ }
+ nodes.addFirst(node); // So that the list is in the downward order they appear in the plan
+ }
+ node = node.getParent();
+ }
+
+ // Merge all mergeable SELECT nodes ...
+ for (LinkedList<PlanNode> mergeable : mergeables.values()) {
+ if (mergeable.size() > 1) {
+ Iterator<PlanNode> iter = mergeable.iterator();
+ PlanNode firstSelect = iter.next();
+ Constraint constraint = firstSelect.getProperty(Property.SELECT_CRITERIA, Constraint.class);
+ while (iter.hasNext()) {
+ PlanNode nextSelect = iter.next();
+ Constraint nextConstraint = nextSelect.getProperty(Property.SELECT_CRITERIA, Constraint.class);
+ constraint = merge((ConstraintType)constraint, (ConstraintType)nextConstraint);
+ nextSelect.extractFromParent();
+ }
+ firstSelect.setProperty(Property.SELECT_CRITERIA, constraint);
+ }
+ }
+ mergeables.clear();
+ }
+ return plan;
+ }
+
+ /**
+ * Obtain the similarity key that will be used to determine whether two SELECT nodes should be merged.
+ *
+ * @param constraint the constraint from the SELECT node
+ * @return the similarity key, or null if the constraint should not be merged
+ */
+ protected abstract SimilarityType getSimilarityKey( Constraint constraint );
+
+ /**
+ * Merge the two constraints.
+ *
+ * @param firstConstraint the first constraint
+ * @param secondConstraint the second constraint
+ * @return the merged constraint
+ */
+ protected abstract Constraint merge( ConstraintType firstConstraint,
+ ConstraintType secondConstraint );
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/AbstractMergeSelectNodes.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java (rev 0)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -0,0 +1,89 @@
+/*
+ * JBoss DNA (http://www.jboss.org/dna)
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * See the AUTHORS.txt file in the distribution for a full listing of
+ * individual contributors.
+ *
+ * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
+ * is licensed to you under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * JBoss DNA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.graph.query.optimize;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import net.jcip.annotations.Immutable;
+import org.jboss.dna.graph.query.model.Constraint;
+import org.jboss.dna.graph.query.model.DynamicOperand;
+import org.jboss.dna.graph.query.model.SetCriteria;
+import org.jboss.dna.graph.query.model.StaticOperand;
+
+/**
+ * An {@link OptimizerRule optimizer rule} that merges SELECT nodes that have {@link SetCriteria} applied to the same column on
+ * the same selector.
+ */
+@Immutable
+public class MergeSetCriteria extends AbstractMergeSelectNodes<DynamicOperand, SetCriteria> {
+
+ public static final MergeSetCriteria INSTANCE = new MergeSetCriteria();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.query.optimize.AbstractMergeSelectNodes#getSimilarityKey(org.jboss.dna.graph.query.model.Constraint)
+ */
+ @Override
+ protected DynamicOperand getSimilarityKey( Constraint constraint ) {
+ if (constraint instanceof SetCriteria) {
+ // Look for the list of plan nodes for this operand ...
+ return ((SetCriteria)constraint).getLeftOperand();
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.query.optimize.AbstractMergeSelectNodes#merge(org.jboss.dna.graph.query.model.Constraint,
+ * org.jboss.dna.graph.query.model.Constraint)
+ */
+ @Override
+ protected Constraint merge( SetCriteria firstConstraint,
+ SetCriteria secondConstraint ) {
+ assert firstConstraint.getLeftOperand().equals(secondConstraint.getLeftOperand());
+ Set<StaticOperand> allOperands = new HashSet<StaticOperand>();
+ List<StaticOperand> orderedOperands = new ArrayList<StaticOperand>(firstConstraint.getRightOperands());
+ allOperands.addAll(firstConstraint.getRightOperands());
+ for (StaticOperand second : secondConstraint.getRightOperands()) {
+ if (allOperands.add(second)) {
+ orderedOperands.add(second);
+ }
+ }
+ return new SetCriteria(firstConstraint.getLeftOperand(), orderedOperands);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
+}
Property changes on: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/MergeSetCriteria.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/PushProjects.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/PushProjects.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/PushProjects.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -65,7 +65,16 @@
// Is there already a PROJECT here ?
assert parentOfProject.getChildCount() == 1; // should only have one child ...
PlanNode child = parentOfProject.getFirstChild(); // should only have one child ...
- if (child.is(Type.PROJECT)) continue;
+ if (child.is(Type.PROJECT)) {
+ // Check to see if there is a PROJECT above the access node ...
+ PlanNode accessParent = access.getParent();
+ if (accessParent == null || accessParent.isNot(Type.PROJECT)) continue;
+ // Otherwise, the parent is a PROJECT, but there is another PROJECT above the ACCESS node.
+ // Remove the lower PROJECT so the next code block moves the top PROJECT down below the ACCESS node ...
+ assert accessParent.is(Type.PROJECT);
+ child.extractFromParent();
+ child = parentOfProject.getFirstChild();
+ }
// If the parent of the ACCESS node is a PROJECT, then we can simply move it to here ...
PlanNode accessParent = access.getParent();
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/PushSelectCriteria.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/PushSelectCriteria.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/PushSelectCriteria.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -297,6 +297,7 @@
// first look for originating nodes that exactly match the required selectors ...
for (PlanNode originatingNode : originatingNodes) {
+ if (!criteriaNode.isAbove(originatingNode)) continue;
if (originatingNode.getSelectors().equals(requiredSelectors)) return originatingNode;
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/ReplaceViews.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/ReplaceViews.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/ReplaceViews.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -99,6 +99,7 @@
// The PROJECT from the plan may actually not be needed if there is another PROJECT above it ...
PlanNode node = viewPlan.getParent();
while (node != null) {
+ if (node.isOneOf(Type.JOIN)) break;
if (node.is(Type.PROJECT) && viewPlan.getSelectors().containsAll(node.getSelectors())) {
viewPlan.extractFromParent();
break;
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RewriteIdentityJoins.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RewriteIdentityJoins.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RewriteIdentityJoins.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -25,13 +25,16 @@
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import net.jcip.annotations.Immutable;
import org.jboss.dna.graph.GraphI18n;
import org.jboss.dna.graph.property.ValueFactory;
import org.jboss.dna.graph.query.QueryContext;
+import org.jboss.dna.graph.query.model.Column;
import org.jboss.dna.graph.query.model.EquiJoinCondition;
import org.jboss.dna.graph.query.model.JoinCondition;
+import org.jboss.dna.graph.query.model.SameNodeJoinCondition;
import org.jboss.dna.graph.query.model.SelectorName;
import org.jboss.dna.graph.query.plan.PlanNode;
import org.jboss.dna.graph.query.plan.PlanUtil;
@@ -82,55 +85,68 @@
public PlanNode execute( QueryContext context,
PlanNode plan,
LinkedList<OptimizerRule> ruleStack ) {
+ if (!context.getHints().hasJoin) return plan;
+
// For each of the JOIN nodes ...
Map<SelectorName, SelectorName> rewrittenSelectors = null;
+ int rewrittenJoins = 0;
+ int numJoins = 0;
for (PlanNode joinNode : plan.findAllAtOrBelow(Type.JOIN)) {
+ ++numJoins;
JoinCondition condition = joinNode.getProperty(Property.JOIN_CONDITION, JoinCondition.class);
if (condition instanceof EquiJoinCondition) {
- PlanNode leftNode = joinNode.getFirstChild();
- PlanNode rightNode = joinNode.getLastChild();
+ PlanNode leftNode = joinNode.getFirstChild().findAtOrBelow(Type.SOURCE);
+ PlanNode rightNode = joinNode.getLastChild().findAtOrBelow(Type.SOURCE);
assert leftNode != null;
assert rightNode != null;
- if (leftNode.getType() == Type.SOURCE && rightNode.getType() == Type.SOURCE) {
- EquiJoinCondition equiJoin = (EquiJoinCondition)condition;
- // Find the names (or aliases) of the tables ...
- Schemata schemata = context.getSchemata();
- assert schemata != null;
- SelectorName leftTableName = leftNode.getProperty(Property.SOURCE_NAME, SelectorName.class);
- SelectorName rightTableName = rightNode.getProperty(Property.SOURCE_NAME, SelectorName.class);
- assert leftTableName != null;
- assert rightTableName != null;
- // Presumably the join condition is using at least one alias, but we only care about the actual name ...
- if (!leftTableName.equals(rightTableName)) {
- // The join is not joining the same table, so this doesn't meet the condition ...
- continue;
- }
- // Find the schemata columns referenced by the join condition ...
- Table table = schemata.getTable(leftTableName);
- if (table == null) {
- context.getProblems().addError(GraphI18n.tableDoesNotExist, leftTableName);
- continue;
- }
- ValueFactory<String> stringFactory = context.getExecutionContext().getValueFactories().getStringFactory();
- String leftColumnName = stringFactory.create(equiJoin.getProperty1Name());
- String rightColumnName = stringFactory.create(equiJoin.getProperty2Name());
- Schemata.Column leftColumn = table.getColumn(leftColumnName);
- Schemata.Column rightColumn = table.getColumn(rightColumnName);
- if (leftColumn == null) {
- context.getProblems().addError(GraphI18n.columnDoesNotExistOnTable, leftColumnName, leftTableName);
- continue;
- }
- if (rightColumn == null) {
- context.getProblems().addError(GraphI18n.columnDoesNotExistOnTable, rightColumnName, leftTableName);
- continue;
- }
- // Are the join columns (on both sides) keys?
- if (table.hasKey(leftColumn) && (rightColumn == leftColumn || table.hasKey(rightColumn))) {
- // It meets all the criteria, so rewrite this join node ...
- if (rewrittenSelectors == null) rewrittenSelectors = new HashMap<SelectorName, SelectorName>();
- rewriteJoinNode(context, joinNode, equiJoin, rewrittenSelectors);
- }
+ EquiJoinCondition equiJoin = (EquiJoinCondition)condition;
+ // Find the names (or aliases) of the tables ...
+ Schemata schemata = context.getSchemata();
+ assert schemata != null;
+ SelectorName leftTableName = leftNode.getProperty(Property.SOURCE_NAME, SelectorName.class);
+ SelectorName rightTableName = rightNode.getProperty(Property.SOURCE_NAME, SelectorName.class);
+ assert leftTableName != null;
+ assert rightTableName != null;
+ // Presumably the join condition is using at least one alias, but we only care about the actual name ...
+ if (!leftTableName.equals(rightTableName)) {
+ // The join is not joining the same table, so this doesn't meet the condition ...
+ continue;
}
+ // Find the schemata columns referenced by the join condition ...
+ Table table = schemata.getTable(leftTableName);
+ if (table == null) {
+ context.getProblems().addError(GraphI18n.tableDoesNotExist, leftTableName);
+ continue;
+ }
+ ValueFactory<String> stringFactory = context.getExecutionContext().getValueFactories().getStringFactory();
+ String leftColumnName = stringFactory.create(equiJoin.getProperty1Name());
+ String rightColumnName = stringFactory.create(equiJoin.getProperty2Name());
+ Schemata.Column leftColumn = table.getColumn(leftColumnName);
+ Schemata.Column rightColumn = table.getColumn(rightColumnName);
+ if (leftColumn == null) {
+ context.getProblems().addError(GraphI18n.columnDoesNotExistOnTable, leftColumnName, leftTableName);
+ continue;
+ }
+ if (rightColumn == null) {
+ context.getProblems().addError(GraphI18n.columnDoesNotExistOnTable, rightColumnName, leftTableName);
+ continue;
+ }
+ // Are the join columns (on both sides) keys?
+ if (table.hasKey(leftColumn) && (rightColumn == leftColumn || table.hasKey(rightColumn))) {
+ // It meets all the criteria, so rewrite this join node ...
+ if (rewrittenSelectors == null) rewrittenSelectors = new HashMap<SelectorName, SelectorName>();
+ rewriteJoinNode(context, joinNode, rewrittenSelectors);
+ ++rewrittenJoins;
+ }
+ } else if (condition instanceof SameNodeJoinCondition) {
+ SameNodeJoinCondition sameNodeCondition = (SameNodeJoinCondition)condition;
+ if (sameNodeCondition.getSelector1Name().equals(sameNodeCondition.getSelector2Name())
+ && sameNodeCondition.getSelector2Path() == null) {
+ // It meets all the criteria, so rewrite this join node ...
+ if (rewrittenSelectors == null) rewrittenSelectors = new HashMap<SelectorName, SelectorName>();
+ rewriteJoinNode(context, joinNode, rewrittenSelectors);
+ ++rewrittenJoins;
+ }
}
}
@@ -140,28 +156,72 @@
// this criteria, so we need to re-run this rule...
ruleStack.addFirst(this);
+ // After this rule is done as is no longer needed, we need to try to push SELECTs and PROJECTs again ...
+ if (!(ruleStack.peekFirst() instanceof PushSelectCriteria)) {
+ // We haven't already added these, so add them now ...
+ ruleStack.addFirst(PushProjects.INSTANCE);
+ if (context.getHints().hasCriteria) {
+ ruleStack.addFirst(PushSelectCriteria.INSTANCE);
+ }
+ }
+
// Now rewrite the various portions of the plan that make use of the now-removed selectors ...
PlanUtil.replaceReferencesToRemovedSource(context, plan, rewrittenSelectors);
- } else {
- // There are no-untouched JOIN nodes, which means the sole JOIN node was rewritten as a single SOURCE node
- assert plan.findAllAtOrBelow(Type.JOIN).isEmpty();
- context.getHints().hasJoin = false;
+
+ assert rewrittenJoins > 0;
+ if (rewrittenJoins == numJoins) {
+ assert plan.findAllAtOrBelow(Type.JOIN).isEmpty();
+ context.getHints().hasJoin = false;
+ }
}
return plan;
}
protected void rewriteJoinNode( QueryContext context,
PlanNode joinNode,
- EquiJoinCondition joinCondition,
Map<SelectorName, SelectorName> rewrittenSelectors ) {
// Remove the right source node from the join node ...
- PlanNode rightSource = joinNode.getLastChild();
- rightSource.removeFromParent();
+ PlanNode rightChild = joinNode.getLastChild();
+ rightChild.removeFromParent();
+ PlanNode rightSource = rightChild.findAtOrBelow(Type.SOURCE);
// Replace the join node with the left source node ...
- PlanNode leftSource = joinNode.getFirstChild();
+ PlanNode leftChild = joinNode.getFirstChild();
joinNode.extractFromParent();
+ PlanNode leftSource = leftChild.findAtOrBelow(Type.SOURCE);
+ // Combine the right PROJECT node with that on the left ...
+ PlanNode rightProject = rightChild.findAtOrBelow(Type.PROJECT);
+ if (rightProject != null) {
+ PlanNode leftProject = leftChild.findAtOrBelow(Type.PROJECT);
+ if (leftProject != null) {
+ List<Column> leftColumns = leftProject.getPropertyAsList(Property.PROJECT_COLUMNS, Column.class);
+ for (Column rightColumn : rightProject.getPropertyAsList(Property.PROJECT_COLUMNS, Column.class)) {
+ if (!leftColumns.contains(rightColumn)) leftColumns.add(rightColumn);
+ }
+ } else {
+ // Just create a project on the left side ...
+ leftProject = new PlanNode(Type.PROJECT);
+ leftProject.setProperty(Property.PROJECT_COLUMNS, rightProject.getProperty(Property.PROJECT_COLUMNS));
+ leftChild.getFirstChild().insertAsParent(leftProject);
+ }
+ }
+
+ // Accumulate any SELECT nodes from the right side and add to the left ...
+ PlanNode topRightSelect = rightChild.findAtOrBelow(Type.SELECT);
+ if (topRightSelect != null) {
+ PlanNode bottomRightSelect = topRightSelect;
+ while (true) {
+ if (bottomRightSelect.getFirstChild().isNot(Type.SELECT)) break;
+ bottomRightSelect = bottomRightSelect.getFirstChild();
+ }
+ topRightSelect.setParent(null);
+ bottomRightSelect.removeAllChildren();
+ // Place just above the left source ...
+ leftSource.getParent().addLastChild(topRightSelect);
+ leftSource.setParent(bottomRightSelect);
+ }
+
// Now record that references to the right selector name should be removed ...
SelectorName rightTableName = rightSource.getProperty(Property.SOURCE_NAME, SelectorName.class);
SelectorName rightTableAlias = rightSource.getProperty(Property.SOURCE_ALIAS, SelectorName.class);
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizer.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -69,8 +69,10 @@
*/
protected void populateRuleStack( LinkedList<OptimizerRule> ruleStack,
PlanHints hints ) {
+ ruleStack.addFirst(MergeSetCriteria.INSTANCE);
if (hints.hasJoin) {
ruleStack.addFirst(ChooseJoinAlgorithm.USE_ONLY_NESTED_JOIN_ALGORITHM);
+ ruleStack.addFirst(RewriteIdentityJoins.INSTANCE);
}
ruleStack.addFirst(PushProjects.INSTANCE);
if (hints.hasCriteria) {
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/CanonicalPlanner.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/CanonicalPlanner.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/CanonicalPlanner.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -70,6 +70,8 @@
* |
* PROJECT with the list of columns being SELECTed
* |
+ * GROUP if 'GROUP BY' is used
+ * |
* SELECT1
* | One or more SELECT plan nodes that each have
* SELECT2 a single non-join constraint that are then all AND-ed
@@ -127,6 +129,9 @@
// Attach criteria (on top) ...
plan = attachCriteria(context, plan, query.getConstraint());
+ // Attach groupbys (on top) ...
+ // plan = attachGrouping(context,plan,query.getGroupBy());
+
// Attach the project ...
plan = attachProject(context, plan, query.getColumns(), usedSources);
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanNode.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanNode.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanNode.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -173,6 +173,12 @@
PROJECT_COLUMNS,
/**
+ * For GROUP nodes, the ordered collection of columns used to group the result tuples. Value is a Collection of
+ * {@link Column} objects.
+ */
+ GROUP_COLUMNS,
+
+ /**
* For SET_OPERATION nodes, the list of orderings for the results. Value is either a Collection of {@link Ordering}
* objects or a collection of {@link SelectorName} objects (if the sorting is being done as an input to a merge-join).
*/
@@ -363,6 +369,31 @@
}
/**
+ * Determine if the supplied node is an ancestor of this node.
+ *
+ * @param possibleAncestor the node that is to be determined if it is an ancestor
+ * @return true if the supplied node is indeed an ancestor, or false if it is not an ancestor
+ */
+ public boolean isBelow( PlanNode possibleAncestor ) {
+ PlanNode node = this;
+ while (node != null) {
+ if (node == possibleAncestor) return true;
+ node = node.getParent();
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the supplied node is a descendant of this node.
+ *
+ * @param possibleDescendant the node that is to be determined if it is a descendant
+ * @return true if the supplied node is indeed an ancestor, or false if it is not an ancestor
+ */
+ public boolean isAbove( PlanNode possibleDescendant ) {
+ return possibleDescendant != null && possibleDescendant.isBelow(this);
+ }
+
+ /**
* Get the parent of this node.
*
* @return the parent node, or null if this node has no parent
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanUtil.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanUtil.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanUtil.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -23,6 +23,7 @@
*/
package org.jboss.dna.graph.query.plan;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -489,11 +490,10 @@
List<PlanNode> potentiallyRemovableSources = new LinkedList<PlanNode>();
do {
// Remove the view from the selectors ...
- if (node.getSelectors().contains(viewName)) {
+ if (node.getSelectors().remove(viewName)) {
switch (node.getType()) {
case PROJECT:
// Adjust the columns ...
- node.getSelectors().remove(viewName);
List<Column> columns = node.getPropertyAsList(Property.PROJECT_COLUMNS, Column.class);
if (columns != null) {
for (int i = 0; i != columns.size(); ++i) {
@@ -529,19 +529,41 @@
node.setProperty(Property.SELECT_CRITERIA, newConstraint);
}
break;
- case SET_OPERATION:
- break;
case SOURCE:
SelectorName sourceName = node.getProperty(Property.SOURCE_NAME, SelectorName.class);
assert sourceName.equals(sourceName); // selector name already matches
potentiallyRemovableSources.add(node);
break;
- default:
+ case JOIN:
+ JoinCondition joinCondition = node.getProperty(Property.JOIN_CONDITION, JoinCondition.class);
+ JoinCondition newJoinCondition = replaceViewReferences(context, joinCondition, mappings, node);
+ node.getSelectors().clear();
+ node.setProperty(Property.JOIN_CONDITION, newJoinCondition);
+ node.addSelectors(Visitors.getSelectorsReferencedBy(newJoinCondition));
+ List<Constraint> joinConstraints = node.getPropertyAsList(Property.JOIN_CONSTRAINTS, Constraint.class);
+ if (joinConstraints != null && !joinConstraints.isEmpty()) {
+ List<Constraint> newConstraints = new ArrayList<Constraint>(joinConstraints.size());
+ for (Constraint joinConstraint : joinConstraints) {
+ newConstraint = replaceReferences(context, joinConstraint, mappings, node);
+ newConstraints.add(newConstraint);
+ node.addSelectors(Visitors.getSelectorsReferencedBy(newConstraint));
+ }
+ node.setProperty(Property.JOIN_CONSTRAINTS, newConstraints);
+ }
break;
+ case ACCESS:
+ // Nothing to do here, as the selector names are fixed elsewhere
+ break;
+ case SORT:
+ break;
+ case GROUP:
+ // Don't yet use GROUP BY
+ case SET_OPERATION:
+ case DUP_REMOVE:
+ case LIMIT:
+ case NULL:
+ break;
}
- if (!node.getSelectors().contains(viewName)) {
- // Used to reference view, so it needs to at least reference
- }
}
// Move to the parent ...
node = node.getParent();
@@ -704,10 +726,10 @@
return operand;
}
- public static JoinCondition replaceReferences( QueryContext context,
- JoinCondition joinCondition,
- ColumnMapping mapping,
- PlanNode node ) {
+ public static JoinCondition replaceViewReferences( QueryContext context,
+ JoinCondition joinCondition,
+ ColumnMapping mapping,
+ PlanNode node ) {
if (joinCondition instanceof EquiJoinCondition) {
EquiJoinCondition condition = (EquiJoinCondition)joinCondition;
SelectorName replacement1 = condition.getSelector1Name();
@@ -749,6 +771,7 @@
if (replacement2.equals(viewName)) replacement2 = sourceName;
if (replacement1 == condition.getSelector1Name() && replacement2 == condition.getSelector2Name()) return condition;
node.addSelector(replacement1, replacement2);
+ if (condition.getSelector2Path() == null) return new SameNodeJoinCondition(replacement1, replacement2);
return new SameNodeJoinCondition(replacement1, replacement2, condition.getSelector2Path());
}
if (joinCondition instanceof ChildNodeJoinCondition) {
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/validate/ImmutableSchemata.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/validate/ImmutableSchemata.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/validate/ImmutableSchemata.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -356,7 +356,7 @@
String... columnNames ) {
CheckArg.isNotEmpty(tableName, "tableName");
CheckArg.isNotEmpty(columnNames, "columnNames");
- ImmutableTable existing = tables.get(tableName);
+ ImmutableTable existing = tables.get(new SelectorName(tableName));
if (existing == null) {
throw new IllegalArgumentException(GraphI18n.tableDoesNotExist.text(tableName));
}
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/ReplaceViewsTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/ReplaceViewsTest.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/ReplaceViewsTest.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -24,7 +24,6 @@
package org.jboss.dna.graph.query.optimize;
import static org.hamcrest.core.Is.is;
-import static org.hamcrest.core.IsSame.sameInstance;
import static org.junit.Assert.assertThat;
import java.util.Arrays;
import java.util.LinkedList;
@@ -133,15 +132,12 @@
// Execute the rule ...
PlanNode result = rule.execute(context, project, new LinkedList<OptimizerRule>());
+ System.out.println(project);
System.out.println(result);
- assertThat(result, is(sameInstance(project)));
+ assertThat(result.isSameAs(project), is(true));
assertChildren(project, select1);
assertChildren(select1, select2);
assertChildren(select2, select3);
- assertChildren(select3, source);
- assertSameChildren(source, viewSelect);
- assertSameChildren(source.getFirstChild(), viewSource);
- assertSameChildren(source.getFirstChild().getFirstChild());
}
protected List<Column> columns( Column... columns ) {
Modified: trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizerTest.java
===================================================================
--- trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizerTest.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/query/optimize/RuleBasedOptimizerTest.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -38,12 +38,14 @@
import org.jboss.dna.graph.query.model.Column;
import org.jboss.dna.graph.query.model.Comparison;
import org.jboss.dna.graph.query.model.EquiJoinCondition;
+import org.jboss.dna.graph.query.model.FullTextSearch;
import org.jboss.dna.graph.query.model.JoinType;
import org.jboss.dna.graph.query.model.Literal;
import org.jboss.dna.graph.query.model.Operator;
import org.jboss.dna.graph.query.model.PropertyValue;
import org.jboss.dna.graph.query.model.QueryCommand;
import org.jboss.dna.graph.query.model.SelectorName;
+import org.jboss.dna.graph.query.model.SetCriteria;
import org.jboss.dna.graph.query.parse.SqlQueryParser;
import org.jboss.dna.graph.query.plan.CanonicalPlanner;
import org.jboss.dna.graph.query.plan.JoinAlgorithm;
@@ -66,6 +68,7 @@
private List<Integer> ruleExecutionOrder;
private QueryContext context;
private PlanNode node;
+ private boolean print = false;
@Before
public void beforeEach() {
@@ -73,8 +76,15 @@
ImmutableSchemata.Builder builder = ImmutableSchemata.createBuilder(execContext);
builder.addTable("t1", "c11", "c12", "c13");
builder.addTable("t2", "c21", "c22", "c23");
+ builder.addTable("all", "a1", "a2", "a3", "a4", "primaryType", "mixins");
+ builder.addKey("all", "a1");
+ builder.addKey("all", "a3");
builder.addView("v1", "SELECT c11, c12 AS c2 FROM t1 WHERE c13 < CAST('3' AS LONG)");
builder.addView("v2", "SELECT t1.c11, t1.c12, t2.c23 FROM t1 JOIN t2 ON t1.c11 = t2.c21");
+ builder.addView("type1",
+ "SELECT all.a1, all.a2 FROM all WHERE all.primaryType IN ('t1','t0') AND all.mixins IN ('t3','t4')");
+ builder.addView("type2",
+ "SELECT all.a3, all.a4 FROM all WHERE all.primaryType IN ('t2','t0') AND all.mixins IN ('t4','t5')");
Schemata schemata = builder.build();
context = new QueryContext(execContext, new PlanHints(), schemata);
@@ -282,6 +292,136 @@
assertThat(node.isSameAs(project), is(true));
}
+ @Test
+ public void shouldOptimizePlanForQueryUsingTypeView() {
+ node = optimize("SELECT type1.a1 AS a, type1.a2 AS b FROM type1 WHERE CONTAINS(type1.a2,'something')");
+
+ // Create the expected plan ...
+ PlanNode access = new PlanNode(Type.ACCESS, selector("all"));
+ PlanNode project = new PlanNode(Type.PROJECT, access, selector("all"));
+ project.setProperty(Property.PROJECT_COLUMNS, columns(column("all", "a1", "a"), column("all", "a2", "b")));
+ PlanNode select1 = new PlanNode(Type.SELECT, project, selector("all"));
+ select1.setProperty(Property.SELECT_CRITERIA, new FullTextSearch(selector("all"), name("a2"), "something"));
+ PlanNode select2 = new PlanNode(Type.SELECT, select1, selector("all"));
+ select2.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("primaryType")),
+ new Literal("t1"), new Literal("t0")));
+ PlanNode select3 = new PlanNode(Type.SELECT, select2, selector("all"));
+ select3.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("mixins")),
+ new Literal("t3"), new Literal("t4")));
+ PlanNode source = new PlanNode(Type.SOURCE, select3, selector("all"));
+ source.setProperty(Property.SOURCE_NAME, selector("all"));
+ source.setProperty(Property.SOURCE_COLUMNS, context.getSchemata().getTable(selector("all")).getColumns());
+
+ // Compare the expected and actual plan ...
+ assertThat(node.isSameAs(access), is(true));
+ }
+
+ @Test
+ public void shouldOptimizePlanForQueryJoiningMultipleTypeViewsUsingIdentityEquiJoin() {
+ node = optimize("SELECT type1.a1 AS a, type1.a2 AS b, type2.a3 as c, type2.a4 as d "
+ + "FROM type1 JOIN type2 ON type1.a1 = type2.a3 WHERE CONTAINS(type1.a2,'something')");
+
+ // Create the expected plan ...
+ PlanNode access = new PlanNode(Type.ACCESS, selector("all"));
+ PlanNode project = new PlanNode(Type.PROJECT, access, selector("all"));
+ project.setProperty(Property.PROJECT_COLUMNS, columns(column("all", "a1", "a"),
+ column("all", "a2", "b"),
+ column("all", "a3", "c"),
+ column("all", "a4", "d")));
+ PlanNode select1 = new PlanNode(Type.SELECT, project, selector("all"));
+ select1.setProperty(Property.SELECT_CRITERIA, new FullTextSearch(selector("all"), name("a2"), "something"));
+ PlanNode select2 = new PlanNode(Type.SELECT, select1, selector("all"));
+ select2.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("primaryType")),
+ new Literal("t1"), new Literal("t0"), new Literal("t2")));
+ PlanNode select3 = new PlanNode(Type.SELECT, select2, selector("all"));
+ select3.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("mixins")),
+ new Literal("t3"), new Literal("t4"), new Literal("t5")));
+ PlanNode source = new PlanNode(Type.SOURCE, select3, selector("all"));
+ source.setProperty(Property.SOURCE_NAME, selector("all"));
+ source.setProperty(Property.SOURCE_COLUMNS, context.getSchemata().getTable(selector("all")).getColumns());
+
+ // Compare the expected and actual plan ...
+ assertThat(node.isSameAs(access), is(true));
+ }
+
+ @Test
+ public void shouldOptimizePlanForQueryJoiningMultipleTypeViewsUsingNonIdentityEquiJoin() {
+ node = optimize("SELECT type1.a1 AS a, type1.a2 AS b, type2.a3 as c, type2.a4 as d "
+ + "FROM type1 JOIN type2 ON type1.a2 = type2.a3 WHERE CONTAINS(type1.a1,'something')");
+
+ // Create the expected plan ...
+ PlanNode project = new PlanNode(Type.PROJECT, selector("all"));
+ project.setProperty(Property.PROJECT_COLUMNS, columns(column("all", "a1", "a"),
+ column("all", "a2", "b"),
+ column("all", "a3", "c"),
+ column("all", "a4", "d")));
+ PlanNode select1 = new PlanNode(Type.SELECT, project, selector("all"));
+ select1.setProperty(Property.SELECT_CRITERIA, new FullTextSearch(selector("all"), name("a1"), "something"));
+ PlanNode join = new PlanNode(Type.JOIN, select1, selector("all"));
+ join.setProperty(Property.JOIN_ALGORITHM, JoinAlgorithm.NESTED_LOOP);
+ join.setProperty(Property.JOIN_TYPE, JoinType.INNER);
+ join.setProperty(Property.JOIN_CONDITION, new EquiJoinCondition(selector("all"), name("a2"), selector("all"), name("a3")));
+
+ PlanNode leftAccess = new PlanNode(Type.ACCESS, join, selector("all"));
+ PlanNode leftProject = new PlanNode(Type.PROJECT, leftAccess, selector("all"));
+ leftProject.setProperty(Property.PROJECT_COLUMNS, columns(column("all", "a1"), column("all", "a2")));
+ PlanNode leftSelect1 = new PlanNode(Type.SELECT, leftProject, selector("all"));
+ leftSelect1.setProperty(Property.SELECT_CRITERIA,
+ new SetCriteria(new PropertyValue(selector("all"), name("primaryType")), new Literal("t1"),
+ new Literal("t0")));
+ PlanNode leftSelect2 = new PlanNode(Type.SELECT, leftSelect1, selector("all"));
+ leftSelect2.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("mixins")),
+ new Literal("t3"), new Literal("t4")));
+ PlanNode leftSource = new PlanNode(Type.SOURCE, leftSelect2, selector("all"));
+ leftSource.setProperty(Property.SOURCE_NAME, selector("all"));
+ leftSource.setProperty(Property.SOURCE_COLUMNS, context.getSchemata().getTable(selector("all")).getColumns());
+
+ PlanNode rightAccess = new PlanNode(Type.ACCESS, join, selector("all"));
+ PlanNode rightProject = new PlanNode(Type.PROJECT, rightAccess, selector("all"));
+ rightProject.setProperty(Property.PROJECT_COLUMNS, columns(column("all", "a3"), column("all", "a4")));
+ PlanNode rightSelect1 = new PlanNode(Type.SELECT, rightProject, selector("all"));
+ rightSelect1.setProperty(Property.SELECT_CRITERIA,
+ new SetCriteria(new PropertyValue(selector("all"), name("primaryType")), new Literal("t2"),
+ new Literal("t0")));
+ PlanNode rightSelect2 = new PlanNode(Type.SELECT, rightSelect1, selector("all"));
+ rightSelect2.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("mixins")),
+ new Literal("t4"), new Literal("t5")));
+ PlanNode rightSource = new PlanNode(Type.SOURCE, rightSelect2, selector("all"));
+ rightSource.setProperty(Property.SOURCE_NAME, selector("all"));
+ rightSource.setProperty(Property.SOURCE_COLUMNS, context.getSchemata().getTable(selector("all")).getColumns());
+
+ // Compare the expected and actual plan ...
+ assertThat(node.isSameAs(project), is(true));
+ }
+
+ @Test
+ public void shouldOptimizePlanForQueryJoiningMultipleTypeViewsUsingSameNodeJoin() {
+ node = optimize("SELECT type1.a1 AS a, type1.a2 AS b, type2.a3 as c, type2.a4 as d "
+ + "FROM type1 JOIN type2 ON ISSAMENODE(type1,type2) WHERE CONTAINS(type1.a2,'something')");
+
+ // Create the expected plan ...
+ PlanNode access = new PlanNode(Type.ACCESS, selector("all"));
+ PlanNode project = new PlanNode(Type.PROJECT, access, selector("all"));
+ project.setProperty(Property.PROJECT_COLUMNS, columns(column("all", "a1", "a"),
+ column("all", "a2", "b"),
+ column("all", "a3", "c"),
+ column("all", "a4", "d")));
+ PlanNode select1 = new PlanNode(Type.SELECT, project, selector("all"));
+ select1.setProperty(Property.SELECT_CRITERIA, new FullTextSearch(selector("all"), name("a2"), "something"));
+ PlanNode select2 = new PlanNode(Type.SELECT, select1, selector("all"));
+ select2.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("primaryType")),
+ new Literal("t1"), new Literal("t0"), new Literal("t2")));
+ PlanNode select3 = new PlanNode(Type.SELECT, select2, selector("all"));
+ select3.setProperty(Property.SELECT_CRITERIA, new SetCriteria(new PropertyValue(selector("all"), name("mixins")),
+ new Literal("t3"), new Literal("t4"), new Literal("t5")));
+ PlanNode source = new PlanNode(Type.SOURCE, select3, selector("all"));
+ source.setProperty(Property.SOURCE_NAME, selector("all"));
+ source.setProperty(Property.SOURCE_COLUMNS, context.getSchemata().getTable(selector("all")).getColumns());
+
+ // Compare the expected and actual plan ...
+ assertThat(node.isSameAs(access), is(true));
+ }
+
// ----------------------------------------------------------------------------------------------------------------
// Utility methods ...
// ----------------------------------------------------------------------------------------------------------------
@@ -313,9 +453,11 @@
assertThat("Problems planning query: " + sql + "\n" + problems, problems.hasErrors(), is(false));
PlanNode optimized = new RuleBasedOptimizer().optimize(context, plan);
assertThat("Problems optimizing query: " + sql + "\n" + problems, problems.hasErrors(), is(false));
- System.out.println();
- System.out.println(sql);
- System.out.println(optimized);
+ if (print) {
+ System.out.println();
+ System.out.println(sql);
+ System.out.println(optimized);
+ }
return optimized;
}
}
Modified: trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/xpath/XPathToQueryTranslatorTest.java
===================================================================
--- trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/xpath/XPathToQueryTranslatorTest.java 2009-10-20 16:14:27 UTC (rev 1297)
+++ trunk/dna-jcr/src/test/java/org/jboss/dna/jcr/xpath/XPathToQueryTranslatorTest.java 2009-10-21 17:01:35 UTC (rev 1298)
@@ -73,7 +73,7 @@
@Test
public void shouldTranslateFromXPathContainingExplicitPath() {
assertThat(xpath("/jcr:root/a"),
- isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'a' AND DEPTH(nodeSet1) = 1"));
+ isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'a' AND DEPTH(nodeSet1) = CAST(1 AS LONG)"));
assertThat(xpath("/jcr:root/a/b"), isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) = '/a/b'"));
assertThat(xpath("/jcr:root/a/b/c"), isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) = '/a/b/c'"));
assertThat(xpath("/jcr:root/a/b/c/d"), isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 WHERE PATH(nodeSet1) = '/a/b/c/d'"));
@@ -218,13 +218,13 @@
@Test
public void shouldTranslateFromXPathOfNodeWithNameUnderRoot() {
assertThat(xpath("/jcr:root/element(nodeName,*)"),
- isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName' AND DEPTH(nodeSet1) = 1"));
+ isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName' AND DEPTH(nodeSet1) = CAST(1 AS LONG)"));
assertThat(xpath("/jcr:root/nodeName"),
- isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName' AND DEPTH(nodeSet1) = 1"));
+ isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName' AND DEPTH(nodeSet1) = CAST(1 AS LONG)"));
assertThat(xpath("nodeName"),
- isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName' AND DEPTH(nodeSet1) = 1"));
+ isSql("SELECT * FROM __ALLNODES__ AS nodeSet1 WHERE NAME(nodeSet1) = 'nodeName' AND DEPTH(nodeSet1) = CAST(1 AS LONG)"));
}
@Test
16 years, 2 months
DNA SVN: r1297 - in trunk/docs/reference/src/main/docbook/en-US: content/core and 1 other directory.
by dna-commits@lists.jboss.org
Author: bcarothers
Date: 2009-10-20 12:14:27 -0400 (Tue, 20 Oct 2009)
New Revision: 1297
Modified:
trunk/docs/reference/src/main/docbook/en-US/content/core/graph.xml
trunk/docs/reference/src/main/docbook/en-US/custom.dtd
Log:
DNA-523 Spelling and grammar errors in on-line JBoss DNA Reference Guide
Committed patch that corrects all of the noted grammar errors.
Modified: trunk/docs/reference/src/main/docbook/en-US/content/core/graph.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/core/graph.xml 2009-10-19 20:26:00 UTC (rev 1296)
+++ trunk/docs/reference/src/main/docbook/en-US/content/core/graph.xml 2009-10-20 16:14:27 UTC (rev 1297)
@@ -105,7 +105,7 @@
via the <code>getValueFactories()</code> method. But before we see that, let's first discuss how names are represented as strings.
</para>
<para>
- We'll see how names are used later one, but one more point to make: &Name; is both serializable and comparable,
+ We'll see how names are used later on, but one more point to make: &Name; is both serializable and comparable,
and all implementations should support <code>equals(...)</code> and <code>hashCode()</code> so that &Name; can
be used as a key in a hash-based map. &Name; also extends the &Readable; interface, which we'll learn
more about later in this chapter.
@@ -257,7 +257,7 @@
<para>
JBoss DNA properties can hold a wide range of value objects, including normal Java strings, names, paths,
URIs, booleans, longs, doubles, decimals, binary content, dates, UUIDs, references to other nodes,
- or any other serializable object. All but three these are the standard Java classes: dates are
+ or any other serializable object. All but three of these are the standard Java classes: dates are
represented by an immutable &DateTime; class; binary content is represented by an immutable &Binary;
interface patterned after the proposed interface of the same name in <ulink url="&JSR283;">JSR-283</ulink>;
and &Reference; is an immutable interface patterned after the corresponding interface is
@@ -352,7 +352,7 @@
<sect1 id="graph-value-factories">
<title>Values and value factories</title>
<para>
- JBoss DNA properties can hold a variety of types of value objects: strings, names, paths,
+ JBoss DNA properties can hold a variety of value object types: strings, names, paths,
URIs, booleans, longs, doubles, decimals, binary content, dates, UUIDs, references to other nodes,
or any other serializable object. To assist in the creation of these values and conversion
into other types, JBoss DNA defines a &ValueFactory; interface. This interface is parameterized
@@ -459,7 +459,7 @@
</programlisting>
<para>
What we've glossed over so far, however, is how to obtain the correct &ValueFactory; for the desired type.
- If you remember back to the previous chapter, &ExecutionContext; has a <code>getValueFactories()</code> method
+ If you remember back in the previous chapter, &ExecutionContext; has a <code>getValueFactories()</code> method
that return a &ValueFactories; interface:
</para>
<programlisting>
@@ -597,7 +597,7 @@
<para>
JBoss DNA provides efficient implementations of all of these interfaces: the &ValueFactory; interfaces and subinterfaces;
the &Path;, &PathSegment;, &Name;, &Binary;, &DateTime;, and &Reference; interfaces; and the &ValueFactories; interface
- return by the &ExecutionContext;. In fact, some of these interfaces have multiple implementations that are optimized for
+ returned by the &ExecutionContext;. In fact, some of these interfaces have multiple implementations that are optimized for
specific but frequently-occurring conditions.
</para>
</sect1>
@@ -782,8 +782,8 @@
<para>
JBoss DNA's <emphasis>Graph API</emphasis> was designed as a lightweight public API for working with graph information.
The &Graph; class is the primary class in API, and each instance represents a single, independent
- view of a single graph. &Graph; instances don't maintain state, so every request (or batch of requests) operate against
- the underlying graph and the return <emphasis>immutable snapshots</emphasis> of the requested state at the time
+ view of a single graph. &Graph; instances don't maintain state, so every request (or batch of requests) operates against
+ the underlying graph and then returns <emphasis>immutable snapshots</emphasis> of the requested state at the time
the request was made.
</para>
<para>
@@ -807,8 +807,8 @@
<para>
JBoss DNA graphs have the notion of <emphasis>workspaces</emphasis> that provide different views of the content. Some graphs may have
one workspace, while others may have multiple workspaces. Some graphs will allow a client to create new workspaces or destroy
- existing workspaces, while other graphs will not allow adding or removing workspaces. Some graphs may have workspaces may show the same (or very
- similar) content, while other graphs may have workspaces that each contain completely independent content.
+ existing workspaces, while other graphs will not allow adding or removing workspaces. Some graphs may have workspaces that may show the same (or very
+ similar) content, while other graphs may have workspaces that contain completely independent content.
</para>
<para>
The &Graph; object is always bound to a workspace, which initially is the <emphasis>default workspace</emphasis>. To find out
@@ -1001,7 +1001,7 @@
<row>
<entry>ReadNodeRequest</entry>
<entry>
- A request to read from the named workspace in the source a node's properties and children.
+ A request to read a node's properties and children from the named workspace in the source.
The node may be specified by path and/or by identification properties.
The connector returns all properties and the locations for all children,
or sets a &PathNotFoundException; error on the request if the node did not exist in the workspace.
@@ -1012,7 +1012,7 @@
<row>
<entry>VerifyNodeExistsRequest</entry>
<entry>
- A request to verify the existance of a node at the specified location in the named workspace of the source.
+ A request to verify the existence of a node at the specified location in the named workspace of the source.
The connector returns all the actual location for the node if it exists, or
sets a &PathNotFoundException; error on the request if the node does not exist in the workspace.
The connector sets a &InvalidWorkspaceException; error on the request if the named workspace does not exist.
@@ -1021,7 +1021,7 @@
<row>
<entry>ReadAllPropertiesRequest</entry>
<entry>
- A request to read from the named workspace in the source all of the properties of a node.
+ A request to read all of the properties of a node from the named workspace in the source.
The node may be specified by path and/or by identification properties.
The connector returns all properties that were found on the node,
or sets a &PathNotFoundException; error on the request if the node did not exist in the workspace.
@@ -1032,7 +1032,7 @@
<row>
<entry>ReadPropertyRequest</entry>
<entry>
- A request to read from the named workspace in the source a single property of a node.
+ A request to read a single property of a node from the named workspace in the source.
The node may be specified by path and/or by identification properties,
and the property is specified by name.
The connector returns the property if found on the node,
@@ -1044,7 +1044,7 @@
<row>
<entry>ReadAllChildrenRequest</entry>
<entry>
- A request to read from the named workspace in the source all of the children of a node.
+ A request to read all of the children of a node from the named workspace in the source.
The node may be specified by path and/or by identification properties.
The connector returns an ordered list of locations for each child found on the node,
an empty list if the node had no children,
@@ -1056,7 +1056,7 @@
<row>
<entry>ReadBlockOfChildrenRequest</entry>
<entry>
- A request to read from the named workspace in the source a block of children of a node, starting with the n<superscript>th</superscript> children.
+ A request to read a block of children of a node, starting with the n<superscript>th</superscript> child from the named workspace in the source.
This is designed to allow paging through the children, which is much more efficient for large numbers of children.
The node may be specified by path and/or by identification properties, and the block
is defined by a starting index and a count (i.e., the block size).
@@ -1070,8 +1070,8 @@
<row>
<entry>ReadNextBlockOfChildrenRequest</entry>
<entry>
- A request to read from the named workspace in the source a block of children of a node, starting with the children that immediately follow
- a previously-returned child.
+ A request to read a block of children of a node, starting with the children that immediately follow
+ a previously-returned child from the named workspace in the source.
This is designed to allow paging through the children, which is much more efficient for large numbers of children.
The node may be specified by path and/or by identification properties, and the block
is defined by the location of the node immediately preceding the block and a count (i.e., the block size).
@@ -1336,7 +1336,7 @@
<title>Observable</title>
<para>
Any component that can have changes and be observed can implement the &Observable; interface. This interface
- allows &Observers; to register (or be registered) to receive notifications of the changes. However, a concrete and thread-safe
+ allows &Observer;s to register (or be registered) to receive notifications of the changes. However, a concrete and thread-safe
implementation of this interface, called &ChangeObservers;, is available and should be used where possible, since it
automatically manages the registered &ChangeObserver; instances and properly implements the register and unregister mechanisms.
</para>
Modified: trunk/docs/reference/src/main/docbook/en-US/custom.dtd
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/custom.dtd 2009-10-19 20:26:00 UTC (rev 1296)
+++ trunk/docs/reference/src/main/docbook/en-US/custom.dtd 2009-10-20 16:14:27 UTC (rev 1297)
@@ -53,7 +53,7 @@
<!ENTITY HttpServletRequest "<ulink url='&JavaEE;javax/servlet/http/HttpServletRequest.html'><classname>HttpServletRequest</classname></ulink>">
<!ENTITY Serializable "<ulink url='&Java;java/io/Serializable.html'><interface>Serializable</interface></ulink>">
<!ENTITY Iterator "<ulink url='&Java;java/util/Iterator.html'><interface>Iterator</interface></ulink>">
-<!ENTITY Iteratable "<ulink url='&Java;java/util/Iteratable.html'><interface>Iteratable</interface></ulink>">
+<!ENTITY Iterable "<ulink url='&Java;java/util/Iterable.html'><interface>Iterable</interface></ulink>">
<!ENTITY Set "<ulink url='&Java;java/util/Set.html'><interface>Set</interface></ulink>">
<!ENTITY Map "<ulink url='&Java;java/util/Map.html'><interface>Map</interface></ulink>">
<!ENTITY List "<ulink url='&Java;java/util/List.html'><interface>List</interface></ulink>">
@@ -105,6 +105,7 @@
<!ENTITY Property "<ulink url='&API;graph/property/Property.html'><interface>Property</interface></ulink>">
<!ENTITY DateTime "<ulink url='&API;graph/property/DateTime.html'><interface>DateTime</interface></ulink>">
<!ENTITY Binary "<ulink url='&API;graph/property/Binary.html'><interface>Binary</interface></ulink>">
+<!ENTITY Reference "<ulink url='&API;graph/property/Reference'><interface>Reference</interface></ulink>">
<!ENTITY ValueFactory "<ulink url='&API;graph/property/ValueFactory.html'><interface>ValueFactory</interface></ulink>">
<!ENTITY ValueFactories "<ulink url='&API;graph/property/ValueFactories.html'><interface>ValueFactories</interface></ulink>">
<!ENTITY ValueFormatException "<ulink url='&API;graph/property/ValueFormatException.html'><classname>ValueFormatException</classname></ulink>">
16 years, 2 months