Author: rhauch
Date: 2009-12-02 15:34:00 -0500 (Wed, 02 Dec 2009)
New Revision: 1382
Added:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/AccessQueryRequest.java
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ForkRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinMirrorRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinRequestProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/QueryContext.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/AbstractAccessComponent.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/process/QueryProcessor.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/FullTextSearchRequest.java
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/QueryRequest.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/SearchRequest.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
Log:
DNA-467 Added a new AccessQueryRequest and support in the RequestProcessor and its
implementations. The Graph API now provides methods for submitting queries (in the form
of QueryCommand objects) and full-text searches to the underlying graph and its connector.
The Graph.query(QueryCommand,Schemata) method runs the query through the QueryEngine,
which plans, replaces views, optimizes, validates, and executes the query. The
QueryEngine (with the Graph's tailored Processor implementation) generates a single
AccessQueryRequest for each of the low-level access queries. Access queries are usually
SELECTs against a single table, after all of the view replacement and optimization has
been performed. These access queries are submitted to the connector in a single batch for
each high-level query), ensuring that a query sees only consistent results.
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-12-02 03:59:28 UTC
(rev 1381)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/Graph.java 2009-12-02 20:34:00 UTC
(rev 1382)
@@ -45,6 +45,8 @@
import net.jcip.annotations.Immutable;
import net.jcip.annotations.NotThreadSafe;
import org.jboss.dna.common.collection.EmptyIterator;
+import org.jboss.dna.common.collection.Problems;
+import org.jboss.dna.common.i18n.I18n;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.cache.CachePolicy;
import org.jboss.dna.graph.connector.RepositoryConnection;
@@ -63,12 +65,32 @@
import org.jboss.dna.graph.property.Reference;
import org.jboss.dna.graph.property.ValueFormatException;
import org.jboss.dna.graph.property.Path.Segment;
+import org.jboss.dna.graph.query.QueryContext;
+import org.jboss.dna.graph.query.QueryEngine;
+import org.jboss.dna.graph.query.QueryResults;
+import org.jboss.dna.graph.query.QueryResults.Columns;
+import org.jboss.dna.graph.query.model.QueryCommand;
+import org.jboss.dna.graph.query.model.TypeSystem;
+import org.jboss.dna.graph.query.optimize.Optimizer;
+import org.jboss.dna.graph.query.optimize.RuleBasedOptimizer;
+import org.jboss.dna.graph.query.plan.CanonicalPlanner;
+import org.jboss.dna.graph.query.plan.PlanHints;
+import org.jboss.dna.graph.query.plan.PlanNode;
+import org.jboss.dna.graph.query.plan.Planner;
+import org.jboss.dna.graph.query.process.AbstractAccessComponent;
+import org.jboss.dna.graph.query.process.ProcessingComponent;
+import org.jboss.dna.graph.query.process.Processor;
+import org.jboss.dna.graph.query.process.QueryProcessor;
+import org.jboss.dna.graph.query.process.SelectComponent.Analyzer;
+import org.jboss.dna.graph.query.validate.Schemata;
+import org.jboss.dna.graph.request.AccessQueryRequest;
import org.jboss.dna.graph.request.BatchRequestBuilder;
import org.jboss.dna.graph.request.CacheableRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
import org.jboss.dna.graph.request.CompositeRequest;
import org.jboss.dna.graph.request.CreateNodeRequest;
import org.jboss.dna.graph.request.CreateWorkspaceRequest;
+import org.jboss.dna.graph.request.FullTextSearchRequest;
import org.jboss.dna.graph.request.InvalidRequestException;
import org.jboss.dna.graph.request.InvalidWorkspaceException;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
@@ -165,6 +187,7 @@
protected final RequestBuilder requests;
protected final Conjunction<Graph> nextGraph;
private Workspace currentWorkspace;
+ private QueryEngine queryEngine;
protected Graph( String sourceName,
RepositoryConnectionFactory connectionFactory,
@@ -2451,6 +2474,196 @@
}
/**
+ * Search the current workspace using the supplied full-text search expression.
+ *
+ * @param fullTextSearchExpression the full-text search expression
+ * @return the results of the search; never null
+ * @throws IllegalArgumentException if the expression is null
+ */
+ public QueryResults search( final String fullTextSearchExpression ) {
+ FullTextSearchRequest request = requests.search(getCurrentWorkspaceName(),
fullTextSearchExpression);
+ return request.getResults();
+ }
+
+ /**
+ * Query the current workspace using the supplied {@link Schemata}.
+ *
+ * @param query the query that is to be executed against the current workspace
+ * @param schemata the schemata defining the structure of the tables that are being
queried
+ * @return the interface used to continue specifying the options for the query and to
obtain the results
+ * @throws IllegalArgumentException if the query or schemata references are null
+ */
+ public BuildQuery query( final QueryCommand query,
+ final Schemata schemata ) {
+ CheckArg.isNotNull(query, "query");
+ CheckArg.isNotNull(schemata, "schemata");
+ return new BuildQuery() {
+ private PlanHints hints;
+ private Problems problems;
+ private Map<String, Object> variables;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.Graph.BuildQuery#using(java.util.Map)
+ */
+ public BuildQuery using( Map<String, Object> variables ) {
+ CheckArg.isNotNull(variables, "variables");
+ if (this.variables == null) this.variables = new HashMap<String,
Object>();
+ this.variables.putAll(variables);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.Graph.BuildQuery#using(java.lang.String,
java.lang.Object)
+ */
+ public BuildQuery using( String variableName,
+ Object variableValue ) {
+ CheckArg.isNotNull(variableName, "variableName");
+ if (this.variables == null) this.variables = new HashMap<String,
Object>();
+ this.variables.put(variableName, variableValue);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.Graph.BuildQuery#using(org.jboss.dna.graph.query.plan.PlanHints)
+ */
+ public BuildQuery using( PlanHints hints ) {
+ this.hints = hints;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.Graph.BuildQuery#execute()
+ */
+ public QueryResults execute() {
+ Batch batch = batch();
+ TypeSystem typeSystem =
getContext().getValueFactories().getTypeSystem();
+ QueryContext context = new GraphQueryContext(schemata, typeSystem, hints,
problems, variables, batch);
+ QueryEngine engine = getQueryEngine();
+ return engine.execute(context, query);
+ }
+ };
+ }
+
+ protected QueryEngine getQueryEngine() {
+ if (queryEngine == null) {
+ queryEngine = getQueryEngine(new RuleBasedOptimizer());
+ }
+ return queryEngine;
+ }
+
+ protected QueryEngine getQueryEngine( Optimizer optimizer ) {
+ Planner planner = new CanonicalPlanner();
+ Processor processor = new QueryProcessor() {
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.query.process.QueryProcessor#createAccessComponent(org.jboss.dna.graph.query.model.QueryCommand,
+ * org.jboss.dna.graph.query.QueryContext,
org.jboss.dna.graph.query.plan.PlanNode,
+ * org.jboss.dna.graph.query.QueryResults.Columns,
org.jboss.dna.graph.query.process.SelectComponent.Analyzer)
+ */
+ @Override
+ protected ProcessingComponent createAccessComponent( QueryCommand
originalQuery,
+ QueryContext context,
+ PlanNode accessNode,
+ Columns resultColumns,
+ Analyzer analyzer ) {
+ return new AccessQueryProcessor(getSourceName(),
getCurrentWorkspaceName(), context, resultColumns, accessNode);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.query.process.QueryProcessor#preExecute(QueryContext)
+ */
+ @Override
+ protected void preExecute( QueryContext context ) {
+ // Submit the batch before the processing the query. No need to hold onto
the batch results,
+ // because each ProcessingComponent holds onto its AccessQueryRequest
...
+ ((GraphQueryContext)context).getBatch().execute();
+ }
+ };
+ return new QueryEngine(planner, optimizer, processor);
+ }
+
+ protected class GraphQueryContext extends QueryContext {
+ private final Batch batch;
+
+ protected GraphQueryContext( Schemata schemata,
+ TypeSystem typeSystem,
+ PlanHints hints,
+ Problems problems,
+ Map<String, Object> variables,
+ Batch batch ) {
+ super(schemata, typeSystem, hints, problems, variables);
+ this.batch = batch;
+ assert this.batch != null;
+ }
+
+ /**
+ * Get the {@link Batch} that is being used to execute these queries
+ *
+ * @return the batch; never null
+ */
+ public Batch getBatch() {
+ return batch;
+ }
+ }
+
+ protected static class AccessQueryProcessor extends AbstractAccessComponent {
+ private final AccessQueryRequest accessRequest;
+ private final String graphSourceName;
+
+ protected AccessQueryProcessor( String graphSourceName,
+ String workspaceName,
+ QueryContext context,
+ Columns columns,
+ PlanNode accessNode ) {
+ super(context, columns, accessNode);
+ this.graphSourceName = graphSourceName;
+ accessRequest = new AccessQueryRequest(workspaceName, sourceName,
getColumns(), andedConstraints, limit,
+ context.getVariables());
+ ((GraphQueryContext)context).getBatch().requestQueue.submit(accessRequest);
+ }
+
+ /**
+ * Get the access query request.
+ *
+ * @return the access query request; never null
+ */
+ public AccessQueryRequest getAccessRequest() {
+ return accessRequest;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.query.process.ProcessingComponent#execute()
+ */
+ @Override
+ public List<Object[]> execute() {
+ if (accessRequest.getError() != null) {
+ I18n msg = GraphI18n.errorWhilePerformingQuery;
+ getContext().getProblems().addError(accessRequest.getError(),
+ msg,
+ accessNode.getString(),
+ accessRequest.workspace(),
+ graphSourceName);
+ return emptyTuples();
+ }
+ return accessRequest.getResults().getTuples();
+ }
+
+ }
+
+ /**
* Import the content from the provided stream of XML data, specifying via the
returned {@link ImportInto object} where the
* content is to be imported.
*
@@ -4442,6 +4655,47 @@
}
/**
+ * The interface used to complete a query submission.
+ */
+ public interface BuildQuery {
+ /**
+ * Use the supplied hints when executing the query.
+ *
+ * @param hints the hints
+ * @return this same interface for method chaining purposes; never null
+ * @throws IllegalArgumentException if the hints reference is null
+ */
+ BuildQuery using( PlanHints hints );
+
+ /**
+ * Use the supplied variables when executing the query.
+ *
+ * @param variables the variables
+ * @return this same interface for method chaining purposes; never null
+ * @throws IllegalArgumentException if the variables reference is null
+ */
+ BuildQuery using( Map<String, Object> variables );
+
+ /**
+ * Use the supplied value for the given variable name when executing the query.
+ *
+ * @param variableName the variable value
+ * @param value the value to replace the variable during execution
+ * @return this same interface for method chaining purposes; never null
+ * @throws IllegalArgumentException if the variable name is null
+ */
+ BuildQuery using( String variableName,
+ Object value );
+
+ /**
+ * Execute the query and get the results.
+ *
+ * @return the query results
+ */
+ QueryResults execute();
+ }
+
+ /**
* The interface used to specify the name of a new workspace.
*/
public interface NameWorkspace {
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-12-02 03:59:28
UTC (rev 1381)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/GraphI18n.java 2009-12-02 20:34:00
UTC (rev 1382)
@@ -68,6 +68,7 @@
public static I18n closedRequestProcessor;
public static I18n multipleErrorsWhileExecutingManyRequests;
public static I18n multipleErrorsWhileExecutingRequests;
+ public static I18n errorWhilePerformingAccessQuery;
public static I18n unsupportedRequestType;
public static I18n unableToAddMoreRequestsToAlreadyExecutedBatch;
public static I18n unableToCreateReferenceToNodeWithoutUuid;
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ForkRequestProcessor.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ForkRequestProcessor.java 2009-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/ForkRequestProcessor.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -54,6 +54,7 @@
import org.jboss.dna.graph.property.PathFactory;
import org.jboss.dna.graph.property.PathNotFoundException;
import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.request.AccessQueryRequest;
import org.jboss.dna.graph.request.CloneBranchRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
import org.jboss.dna.graph.request.CompositeRequest;
@@ -63,11 +64,13 @@
import org.jboss.dna.graph.request.DeleteBranchRequest;
import org.jboss.dna.graph.request.DeleteChildrenRequest;
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
+import org.jboss.dna.graph.request.FullTextSearchRequest;
import org.jboss.dna.graph.request.GetWorkspacesRequest;
import org.jboss.dna.graph.request.InvalidRequestException;
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.QueryRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
import org.jboss.dna.graph.request.ReadBlockOfChildrenRequest;
@@ -1709,6 +1712,36 @@
/**
* {@inheritDoc}
*
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.AccessQueryRequest)
+ */
+ @Override
+ public void process( AccessQueryRequest request ) {
+ processUnknownRequest(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.QueryRequest)
+ */
+ @Override
+ public void process( QueryRequest request ) {
+ processUnknownRequest(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.FullTextSearchRequest)
+ */
+ @Override
+ public void process( FullTextSearchRequest request ) {
+ processUnknownRequest(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.jboss.dna.graph.request.processor.RequestProcessor#close()
*/
@Override
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinMirrorRequestProcessor.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinMirrorRequestProcessor.java 2009-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinMirrorRequestProcessor.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -32,6 +32,7 @@
import org.jboss.dna.graph.property.DateTime;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.request.AccessQueryRequest;
import org.jboss.dna.graph.request.CacheableRequest;
import org.jboss.dna.graph.request.CloneBranchRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
@@ -41,9 +42,11 @@
import org.jboss.dna.graph.request.DeleteBranchRequest;
import org.jboss.dna.graph.request.DeleteChildrenRequest;
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
+import org.jboss.dna.graph.request.FullTextSearchRequest;
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.QueryRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
import org.jboss.dna.graph.request.ReadBlockOfChildrenRequest;
@@ -462,4 +465,33 @@
throw new UnsupportedOperationException(); // should never be called
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.AccessQueryRequest)
+ */
+ @Override
+ public void process( AccessQueryRequest request ) {
+ throw new UnsupportedOperationException(); // should never be called
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.QueryRequest)
+ */
+ @Override
+ public void process( QueryRequest request ) {
+ throw new UnsupportedOperationException(); // should never be called
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.FullTextSearchRequest)
+ */
+ @Override
+ public void process( FullTextSearchRequest request ) {
+ throw new UnsupportedOperationException(); // should never be called
+ }
}
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinRequestProcessor.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinRequestProcessor.java 2009-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/connector/federation/JoinRequestProcessor.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -47,6 +47,7 @@
import org.jboss.dna.graph.property.Property;
import org.jboss.dna.graph.property.PropertyFactory;
import org.jboss.dna.graph.property.ValueComparators;
+import org.jboss.dna.graph.request.AccessQueryRequest;
import org.jboss.dna.graph.request.CacheableRequest;
import org.jboss.dna.graph.request.CloneBranchRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
@@ -56,9 +57,11 @@
import org.jboss.dna.graph.request.DeleteBranchRequest;
import org.jboss.dna.graph.request.DeleteChildrenRequest;
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
+import org.jboss.dna.graph.request.FullTextSearchRequest;
import org.jboss.dna.graph.request.GetWorkspacesRequest;
import org.jboss.dna.graph.request.InvalidRequestException;
import org.jboss.dna.graph.request.MoveBranchRequest;
+import org.jboss.dna.graph.request.QueryRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
import org.jboss.dna.graph.request.ReadBranchRequest;
@@ -1121,6 +1124,36 @@
throw new UnsupportedOperationException(); // should never be called, since
it's handled in the ForkProcessor
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.AccessQueryRequest)
+ */
+ @Override
+ public void process( AccessQueryRequest request ) {
+ throw new UnsupportedOperationException(); // should never be called
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.QueryRequest)
+ */
+ @Override
+ public void process( QueryRequest request ) {
+ throw new UnsupportedOperationException(); // should never be called
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.FullTextSearchRequest)
+ */
+ @Override
+ public void process( FullTextSearchRequest request ) {
+ throw new UnsupportedOperationException(); // should never be called
+ }
+
protected boolean checkErrorOrCancel( Request request,
Request sourceRequest ) {
if (sourceRequest.hasError()) {
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/QueryContext.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/QueryContext.java 2009-12-02
03:59:28 UTC (rev 1381)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/QueryContext.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -119,6 +119,17 @@
}
/**
+ * Create a new context that is a copy of the supplied context. This constructor is
useful for subclasses that wish to add
+ * store additional fields in a QueryContext.
+ *
+ * @param original the original context
+ * @throws IllegalArgumentException if the original is null
+ */
+ protected QueryContext( QueryContext original ) {
+ this(original.schemata, original.typeSystem, original.hints, original.problems,
original.variables);
+ }
+
+ /**
* Get the interface for working with literal values and types.
*
* @return the type system; never null
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-12-02
03:59:28 UTC (rev 1381)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/plan/PlanNode.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -53,8 +53,10 @@
* A representation of a single node within a plan tree.
*/
@NotThreadSafe
-public final class PlanNode implements Iterable<PlanNode>, Readable, Cloneable {
+public final class PlanNode implements Iterable<PlanNode>, Readable, Cloneable,
java.io.Serializable {
+ private static final long serialVersionUID = 1L;
+
/**
* An enumeration dictating the type of plan tree nodes.
*/
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/process/AbstractAccessComponent.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/process/AbstractAccessComponent.java 2009-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/process/AbstractAccessComponent.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -29,7 +29,6 @@
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.query.QueryContext;
import org.jboss.dna.graph.query.QueryResults.Columns;
-import org.jboss.dna.graph.query.model.AllNodes;
import org.jboss.dna.graph.query.model.Column;
import org.jboss.dna.graph.query.model.Constraint;
import org.jboss.dna.graph.query.model.Limit;
@@ -61,9 +60,9 @@
PlanNode source = accessNode.findAtOrBelow(Type.SOURCE);
if (source != null) {
this.sourceName = source.getProperty(Property.SOURCE_NAME,
SelectorName.class);
- if (!AllNodes.ALL_NODES_NAME.equals(this.sourceName)) {
- throw new IllegalArgumentException();
- }
+ // if (!AllNodes.ALL_NODES_NAME.equals(this.sourceName)) {
+ // throw new IllegalArgumentException();
+ // }
} else {
throw new IllegalArgumentException();
}
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-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/process/QueryProcessor.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -88,6 +88,7 @@
if (component != null) {
// Now execute the component ...
+ preExecute(context);
tuples = component.execute();
} else {
// There must have been an error ...
@@ -103,6 +104,16 @@
}
/**
+ * A method that can be overridden when a hook is required immediately before the
top-level {@link ProcessingComponent} is
+ * executed. By default, this method does nothing.
+ *
+ * @param context the context in which the query is being executed; may not be null
+ */
+ protected void preExecute( QueryContext context ) {
+ // do nothing ...
+ }
+
+ /**
* Create an {@link Analyzer} implementation that should be used by the non-access
{@link ProcessingComponent}s that evaluate
* criteria. By default, this method returns null, which means that any criteria
evaluation will likely be pushed down under
* an {@link Type#ACCESS ACCESS} node (and thus handled by an
Added: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/AccessQueryRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/AccessQueryRequest.java
(rev 0)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/AccessQueryRequest.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -0,0 +1,219 @@
+/*
+ * 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 java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.jboss.dna.common.util.CheckArg;
+import org.jboss.dna.common.util.HashCode;
+import org.jboss.dna.graph.query.QueryResults.Columns;
+import org.jboss.dna.graph.query.model.Column;
+import org.jboss.dna.graph.query.model.Constraint;
+import org.jboss.dna.graph.query.model.Limit;
+import org.jboss.dna.graph.query.model.SelectorName;
+import org.jboss.dna.graph.query.model.Visitors;
+
+/**
+ * A {@link Request} to issue an access query a graph, where an access query is a
low-level atomic query that is part of a large,
+ * planned query.
+ */
+public class AccessQueryRequest extends SearchRequest {
+
+ private static final Map<String, Object> EMPTY_VARIABLES =
Collections.emptyMap();
+
+ private static final long serialVersionUID = 1L;
+
+ private final String workspaceName;
+ private final SelectorName tableName;
+ private final List<Constraint> andedConstraints;
+ private final Limit limit;
+ private final Columns resultColumns;
+ private final Map<String, Object> variables;
+ private final int hc;
+
+ /**
+ * Create a new request to execute the supplied query against the name workspace.
+ *
+ * @param workspace the name of the workspace to be queried
+ * @param tableName the name of the selector (or table) being queried
+ * @param resultColumns the specification of the expected columns in the result
tuples
+ * @param andedConstraints the list of AND-ed constraints; may be empty or null if
there are no constraints
+ * @param limit the limit on the results; may be null if there is no limit
+ * @param variables the variables that are available to be substituted upon
execution; may be null if there are no variables
+ * @throws IllegalArgumentException if the query or workspace name is null
+ */
+ public AccessQueryRequest( String workspace,
+ SelectorName tableName,
+ Columns resultColumns,
+ List<Constraint> andedConstraints,
+ Limit limit,
+ Map<String, Object> variables ) {
+ CheckArg.isNotNull(workspace, "workspace");
+ CheckArg.isNotNull(tableName, "tableName");
+ CheckArg.isNotNull(resultColumns, "resultColumns");
+ this.workspaceName = workspace;
+ this.tableName = tableName;
+ this.resultColumns = resultColumns;
+ this.andedConstraints = andedConstraints != null ? andedConstraints :
Collections.<Constraint>emptyList();
+ this.variables = variables != null ? variables : EMPTY_VARIABLES;
+ this.limit = limit != null ? limit : Limit.NONE;
+ this.hc = HashCode.compute(workspaceName, tableName, resultColumns);
+ }
+
+ /**
+ * Get the name of the workspace in which the node exists.
+ *
+ * @return the name of the workspace; never null
+ */
+ public String workspace() {
+ return workspaceName;
+ }
+
+ /**
+ * Get the name of the selector (or table) that is being queried.
+ *
+ * @return the selector name; never null
+ */
+ public SelectorName selectorName() {
+ return tableName;
+ }
+
+ /**
+ * Get the specification of the columns for the {@link #getResults() results}.
+ *
+ * @return the column specifications; never null
+ */
+ public Columns resultColumns() {
+ return resultColumns;
+ }
+
+ /**
+ * Get the immutable list of constraints that are AND-ed together in this query.
Every tuple in the {@link #getResults()
+ * results} must satisfy <i>all</i> of these constraints.
+ *
+ * @return the AND-ed constraints; never null but possibly empty if there are no
constraints
+ */
+ public List<Constraint> andedConstraints() {
+ return andedConstraints;
+ }
+
+ /**
+ * The variables that are available to be substituted upon execution.
+ *
+ * @return the variables; never null but possibly empty
+ */
+ public Map<String, Object> variables() {
+ return variables;
+ }
+
+ /**
+ * Get the limit of the result tuples, which can specify a {@link Limit#getRowLimit()
maximum number of rows} as well as an
+ * {@link Limit#getOffset() initial offset} for the first row.
+ *
+ * @return the limit; never null but may be {@link Limit#isUnlimited() unlimited} if
there is no effective limit
+ */
+ public Limit limit() {
+ return limit;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return hc;
+ }
+
+ /**
+ * {@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)) {
+ AccessQueryRequest that = (AccessQueryRequest)obj;
+ if (this.hashCode() != that.hashCode()) return false;
+ if (!this.workspace().equals(that.workspace())) return false;
+ if (!this.selectorName().equals(that.selectorName())) return false;
+ if (!this.limit().equals(that.limit())) return false;
+ if (!this.andedConstraints().equals(that.andedConstraints())) return false;
+ if (!this.resultColumns().equals(that.resultColumns())) return false;
+ if (!this.variables().equals(that.variables())) return false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("query the \"");
+ sb.append(workspaceName).append("\" workspace: SELECT ");
+ boolean first = true;
+ for (Column column : resultColumns().getColumns()) {
+ if (first) first = false;
+ else sb.append(", ");
+ sb.append(column);
+ }
+ sb.append(" FROM ").append(selectorName().getName());
+ if (!andedConstraints.isEmpty()) {
+ sb.append(" WHERE ");
+ first = true;
+ for (Constraint constraint : andedConstraints) {
+ if (first) first = false;
+ else sb.append(" AND ");
+ sb.append(Visitors.readable(constraint));
+ }
+ }
+ if (!limit.isUnlimited()) {
+ sb.append(Visitors.readable(limit));
+ }
+ if (!variables.isEmpty()) {
+ sb.append(" USING <");
+ first = true;
+ for (Map.Entry<String, Object> entry : variables.entrySet()) {
+ if (first) first = false;
+ else sb.append(", ");
+ sb.append(entry.getKey()).append('=');
+ Object value = entry.getValue();
+ if (value instanceof String) {
+ sb.append('"').append(value).append('"');
+ } else {
+ sb.append(value);
+ }
+ }
+ sb.append('>');
+ }
+ return sb.toString();
+ }
+}
Property changes on:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/AccessQueryRequest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/BatchRequestBuilder.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -28,6 +28,7 @@
import java.util.LinkedList;
import java.util.Map;
import net.jcip.annotations.NotThreadSafe;
+import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.NodeConflictBehavior;
import org.jboss.dna.graph.connector.UuidAlreadyExistsException;
@@ -715,6 +716,18 @@
}
/**
+ * Submit any request to this batch.
+ *
+ * @param request the request to be batched; may not be null
+ * @return this builder for method chaining; never null
+ * @throws IllegalArgumentException if the request is null
+ */
+ public BatchRequestBuilder submit( Request request ) {
+ CheckArg.isNotNull(request, "request");
+ return add(request);
+ }
+
+ /**
* {@inheritDoc}
*
* @see java.lang.Object#toString()
Modified:
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/FullTextSearchRequest.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/FullTextSearchRequest.java 2009-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/FullTextSearchRequest.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -51,16 +51,6 @@
}
/**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.Request#isReadOnly()
- */
- @Override
- public boolean isReadOnly() {
- return true;
- }
-
- /**
* Get the full-text search expression that is to be executed.
*
* @return the full-text search expression; never null and never empty
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/QueryRequest.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/QueryRequest.java 2009-12-02
03:59:28 UTC (rev 1381)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/QueryRequest.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -90,16 +90,6 @@
}
/**
- * {@inheritDoc}
- *
- * @see org.jboss.dna.graph.request.Request#isReadOnly()
- */
- @Override
- public boolean isReadOnly() {
- return true;
- }
-
- /**
* Get the query that is to be executed.
*
* @return the query; never null
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-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/RequestBuilder.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -651,4 +651,17 @@
Location target ) {
return process(new UnlockBranchRequest(target, workspaceName));
}
+
+ /**
+ * Create a request to perform a full-text search of the workspace.
+ *
+ * @param workspaceName the name of the workspace containing the node
+ * @param fullTextSearchExpression the full-text search expression
+ * @return the request; never null
+ * @throws IllegalArgumentException if any of the parameters are null or if the
expression is empty
+ */
+ public FullTextSearchRequest search( String workspaceName,
+ String fullTextSearchExpression ) {
+ return process(new FullTextSearchRequest(fullTextSearchExpression,
workspaceName));
+ }
}
Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/SearchRequest.java
===================================================================
---
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/SearchRequest.java 2009-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/SearchRequest.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -35,6 +35,16 @@
private QueryResults results;
/**
+ * {@inheritDoc}
+ *
+ * @see org.jboss.dna.graph.request.Request#isReadOnly()
+ */
+ @Override
+ public final boolean isReadOnly() {
+ return true;
+ }
+
+ /**
* Set the results for this request.
*
* @param results the results
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-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/LoggingRequestProcessor.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -27,6 +27,7 @@
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.GraphI18n;
+import org.jboss.dna.graph.request.AccessQueryRequest;
import org.jboss.dna.graph.request.CloneBranchRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
import org.jboss.dna.graph.request.CompositeRequest;
@@ -34,10 +35,13 @@
import org.jboss.dna.graph.request.CreateNodeRequest;
import org.jboss.dna.graph.request.CreateWorkspaceRequest;
import org.jboss.dna.graph.request.DeleteBranchRequest;
+import org.jboss.dna.graph.request.DeleteChildrenRequest;
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
+import org.jboss.dna.graph.request.FullTextSearchRequest;
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.QueryRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
import org.jboss.dna.graph.request.ReadBlockOfChildrenRequest;
@@ -51,6 +55,7 @@
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.UpdateValuesRequest;
import org.jboss.dna.graph.request.VerifyNodeExistsRequest;
import org.jboss.dna.graph.request.VerifyWorkspaceRequest;
@@ -190,6 +195,18 @@
/**
* {@inheritDoc}
*
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.DeleteChildrenRequest)
+ */
+ @Override
+ public void process( DeleteChildrenRequest 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.MoveBranchRequest)
*/
@Override
@@ -250,6 +267,18 @@
/**
* {@inheritDoc}
*
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.UpdateValuesRequest)
+ */
+ @Override
+ public void process( UpdateValuesRequest 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.CompositeRequest)
*/
@Override
@@ -382,6 +411,42 @@
/**
* {@inheritDoc}
*
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.QueryRequest)
+ */
+ @Override
+ public void process( QueryRequest 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.AccessQueryRequest)
+ */
+ @Override
+ public void process( AccessQueryRequest 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.FullTextSearchRequest)
+ */
+ @Override
+ public void process( FullTextSearchRequest 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-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/main/java/org/jboss/dna/graph/request/processor/RequestProcessor.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -45,6 +45,7 @@
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.Property;
import org.jboss.dna.graph.property.ReferentialIntegrityException;
+import org.jboss.dna.graph.request.AccessQueryRequest;
import org.jboss.dna.graph.request.CacheableRequest;
import org.jboss.dna.graph.request.ChangeRequest;
import org.jboss.dna.graph.request.CloneBranchRequest;
@@ -274,6 +275,8 @@
process((DestroyWorkspaceRequest)request);
} else if (request instanceof UpdateValuesRequest) {
process((UpdateValuesRequest)request);
+ } else if (request instanceof AccessQueryRequest) {
+ process((AccessQueryRequest)request);
} else if (request instanceof QueryRequest) {
process((QueryRequest)request);
} else if (request instanceof FullTextSearchRequest) {
@@ -932,6 +935,20 @@
}
/**
+ * Process a request to query a workspace with an access query, which is is a
low-level atomic query that is part of a larger,
+ * planned query.
+ * <p>
+ * The default implementation of this method behaves as though the implementation
does not support queries by setting an error
+ * on the request
+ * </p>
+ *
+ * @param request the request
+ */
+ public void process( AccessQueryRequest request ) {
+ processUnknownRequest(request);
+ }
+
+ /**
* Process a request to search a workspace.
* <p>
* The default implementation of this method behaves as though the implementation
does not support full-text searches by
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-12-02
03:59:28 UTC (rev 1381)
+++ trunk/dna-graph/src/main/resources/org/jboss/dna/graph/GraphI18n.properties 2009-12-02
20:34:00 UTC (rev 1382)
@@ -56,6 +56,7 @@
closedRequestProcessor = Closed request processor
multipleErrorsWhileExecutingManyRequests = {0} of the many requests resulted in errors:
{1}
multipleErrorsWhileExecutingRequests = {0} of the {1} requests resulted in errors: {2}
+errorWhilePerformingAccessQuery = Error while performing the access query "{0}"
against the content in the "{1}" workspace of the "{2}" source: {3}
unsupportedRequestType = Requests of type "{0}" are unsupported; actual request
was to {1}
unableToAddMoreRequestsToAlreadyExecutedBatch = Unable to add more requests to a batch of
graph requests that has already been executed
unableToCreateReferenceToNodeWithoutUuid = Unable to set a reference to node {0} since it
has no UUID
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-12-02 03:59:28
UTC (rev 1381)
+++ trunk/dna-graph/src/test/java/org/jboss/dna/graph/GraphTest.java 2009-12-02 20:34:00
UTC (rev 1382)
@@ -31,6 +31,7 @@
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.hasItems;
import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.stub;
import java.util.ArrayList;
import java.util.Arrays;
@@ -55,6 +56,19 @@
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.Property;
+import org.jboss.dna.graph.query.QueryResults;
+import org.jboss.dna.graph.query.QueryResults.Columns;
+import org.jboss.dna.graph.query.model.Column;
+import org.jboss.dna.graph.query.model.Constraint;
+import org.jboss.dna.graph.query.model.Limit;
+import org.jboss.dna.graph.query.model.QueryCommand;
+import org.jboss.dna.graph.query.model.SelectorName;
+import org.jboss.dna.graph.query.model.TypeSystem;
+import org.jboss.dna.graph.query.parse.SqlQueryParser;
+import org.jboss.dna.graph.query.process.QueryResultColumns;
+import org.jboss.dna.graph.query.validate.ImmutableSchemata;
+import org.jboss.dna.graph.query.validate.Schemata;
+import org.jboss.dna.graph.request.AccessQueryRequest;
import org.jboss.dna.graph.request.CloneBranchRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
import org.jboss.dna.graph.request.CompositeRequest;
@@ -63,9 +77,12 @@
import org.jboss.dna.graph.request.CreateWorkspaceRequest;
import org.jboss.dna.graph.request.DeleteBranchRequest;
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
+import org.jboss.dna.graph.request.FullTextSearchRequest;
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.QueryRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
import org.jboss.dna.graph.request.ReadBlockOfChildrenRequest;
@@ -107,6 +124,7 @@
private String sourceName;
private MockRepositoryConnection connection;
private LinkedList<Request> executedRequests;
+ private QueryResults nextQueryResults;
private int numberOfExecutions;
/** Populate this with the properties (by location) that are to be read */
private Map<Location, Collection<Property>> properties;
@@ -137,6 +155,8 @@
properties = new HashMap<Location, Collection<Property>>();
children = new HashMap<Location, List<Location>>();
+
+ nextQueryResults = null;
}
static class IsAnyRequest extends ArgumentMatcher<Request> {
@@ -366,6 +386,21 @@
assertThat(read.property(), is(property));
}
+ protected void assertNextRequestAccessQuery( String workspaceName,
+ String tableName,
+ Columns columns,
+ Limit limit,
+ Constraint... andedConstraints ) {
+ Request request = executedRequests.poll();
+ assertThat(request, is(instanceOf(AccessQueryRequest.class)));
+ AccessQueryRequest access = (AccessQueryRequest)request;
+ assertThat(access.workspace(), is(workspaceName));
+ assertThat(access.selectorName().getName(), is(tableName));
+ assertThat(access.resultColumns(), is(columns));
+ assertThat(access.limit(), is(limit));
+ assertThat(access.andedConstraints(), is(Arrays.asList(andedConstraints)));
+ }
+
//
----------------------------------------------------------------------------------------------------------------
// Immediate requests
//
----------------------------------------------------------------------------------------------------------------
@@ -1170,6 +1205,83 @@
assertNoMoreRequests();
}
+ @Test
+ public void shouldPerformSearchWhenConnectorSupportsQueries() {
+ // Set the expected results that will be returned from the connector ...
+ QueryResults expected = mock(QueryResults.class);
+ nextQueryResults = expected;
+
+ // Execute the seach, and verify the results were consumed by the processor ...
+ String fullTextSearchExpression = "term1 term2";
+ QueryResults results = graph.search(fullTextSearchExpression);
+ assertThat(nextQueryResults, is(nullValue()));
+
+ // The actual results should be what the processor returned ...
+ assertThat(results, is(sameInstance(expected)));
+ }
+
+ @Test( expected = InvalidRequestException.class )
+ public void shouldFailToPerformSearchWhenConnectorDoesNotSupportsQueries() {
+ // Set the expected results that will be returned from the connector ...
+ nextQueryResults = null;
+ // Execute the seach, and verify the results were consumed by the processor ...
+ String fullTextSearchExpression = "term1 term2";
+ graph.search(fullTextSearchExpression);
+ }
+
+ @Test
+ public void shouldPerformQueryWhenConnectorSupportsQueries() {
+ // Set the expected results that will be returned from the connector ...
+ QueryResults expected = mock(QueryResults.class);
+ List<Object[]> tuples = Collections.singletonList(new Object[]
{"v1", "v2", "v3"});
+ stub(expected.getTuples()).toReturn(tuples);
+ nextQueryResults = expected;
+
+ // Execute the query, and verify the results were consumed by the processor ...
+ TypeSystem typeSystem = context.getValueFactories().getTypeSystem();
+ Schemata schemata =
ImmutableSchemata.createBuilder(typeSystem).addTable("t1", "c1",
"c2", "c3").build();
+ QueryCommand query = new SqlQueryParser().parseQuery("SELECT * FROM
t1", typeSystem);
+ QueryResults results = graph.query(query, schemata).execute();
+ assertThat(nextQueryResults, is(nullValue()));
+
+ // The actual results should be what the processor returned ...
+ List<Object[]> actualTuples = results.getTuples();
+ assertThat(actualTuples, is(tuples));
+ assertNextRequestAccessQuery(graph.getCurrentWorkspaceName(), "t1",
columns("t1", "c1", "c2", "c3"), Limit.NONE);
+ }
+
+ @Test( expected = InvalidRequestException.class )
+ public void shouldFailToPerformQueryWhenConnectorDoesNotSupportsQueries() {
+ // Set the expected results that will be returned from the connector ...
+ nextQueryResults = null;
+
+ // Execute the query, and verify the results were consumed by the processor ...
+ TypeSystem typeSystem = context.getValueFactories().getTypeSystem();
+ Schemata schemata =
ImmutableSchemata.createBuilder(typeSystem).addTable("t1", "c1",
"c2", "c3").build();
+ QueryCommand query = new SqlQueryParser().parseQuery("SELECT * FROM
t1", typeSystem);
+ graph.query(query, schemata).execute();
+ }
+
+ protected Columns columns( String tableName,
+ String... columnNames ) {
+ return new QueryResultColumns(columnList(tableName, columnNames), false);
+ }
+
+ protected Columns columnsWithScores( String tableName,
+ String... columnNames ) {
+ return new QueryResultColumns(columnList(tableName, columnNames), true);
+ }
+
+ protected List<Column> columnList( String tableName,
+ String... columnNames ) {
+ List<Column> columns = new ArrayList<Column>();
+ SelectorName selectorName = new SelectorName(tableName);
+ for (String columnName : columnNames) {
+ columns.add(new Column(selectorName, columnName, columnName));
+ }
+ return columns;
+ }
+
//
----------------------------------------------------------------------------------------------------------------
// Implementation of RepositoryConnection and RequestProcessor for tests
//
----------------------------------------------------------------------------------------------------------------
@@ -1343,6 +1455,48 @@
request.setActualRootLocation(Location.create(context.getValueFactories().getPathFactory().createRootPath()));
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.AccessQueryRequest)
+ */
+ @Override
+ public void process( AccessQueryRequest request ) {
+ if (nextQueryResults == null) {
+ super.process(request); // should result in error
+ }
+ request.setResults(nextQueryResults);
+ nextQueryResults = null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.FullTextSearchRequest)
+ */
+ @Override
+ public void process( FullTextSearchRequest request ) {
+ if (nextQueryResults == null) {
+ super.process(request); // should result in error
+ }
+ request.setResults(nextQueryResults);
+ nextQueryResults = null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.QueryRequest)
+ */
+ @Override
+ public void process( QueryRequest request ) {
+ if (nextQueryResults == null) {
+ super.process(request); // should result in error
+ }
+ request.setResults(nextQueryResults);
+ nextQueryResults = null;
+ }
+
private Location actualLocationOf( Location location ) {
// If the location has a path, then use the location
if (location.hasPath()) return location;
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-12-02
03:59:28 UTC (rev 1381)
+++
trunk/dna-graph/src/test/java/org/jboss/dna/graph/connector/MockRepositoryRequestProcessor.java 2009-12-02
20:34:00 UTC (rev 1382)
@@ -26,6 +26,7 @@
import java.util.Queue;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Location;
+import org.jboss.dna.graph.request.AccessQueryRequest;
import org.jboss.dna.graph.request.CloneBranchRequest;
import org.jboss.dna.graph.request.CloneWorkspaceRequest;
import org.jboss.dna.graph.request.CopyBranchRequest;
@@ -33,9 +34,11 @@
import org.jboss.dna.graph.request.CreateWorkspaceRequest;
import org.jboss.dna.graph.request.DeleteBranchRequest;
import org.jboss.dna.graph.request.DestroyWorkspaceRequest;
+import org.jboss.dna.graph.request.FullTextSearchRequest;
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.QueryRequest;
import org.jboss.dna.graph.request.ReadAllChildrenRequest;
import org.jboss.dna.graph.request.ReadAllPropertiesRequest;
import org.jboss.dna.graph.request.ReadBlockOfChildrenRequest;
@@ -328,11 +331,40 @@
/**
* {@inheritDoc}
*
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.AccessQueryRequest)
+ */
+ @Override
+ public void process( AccessQueryRequest request ) {
+ record(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.QueryRequest)
+ */
+ @Override
+ public void process( QueryRequest request ) {
+ record(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see
org.jboss.dna.graph.request.processor.RequestProcessor#process(org.jboss.dna.graph.request.FullTextSearchRequest)
+ */
+ @Override
+ public void process( FullTextSearchRequest request ) {
+ record(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see
org.jboss.dna.graph.request.processor.RequestProcessor#processUnknownRequest(org.jboss.dna.graph.request.Request)
*/
@Override
protected void processUnknownRequest( Request request ) {
record(request);
}
-
}