You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by cl...@apache.org on 2014/10/15 20:42:27 UTC

[50/51] [partial] added missing querybuilder code.

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder
----------------------------------------------------------------------
diff --git a/jena-extras/jena-querybuilder b/jena-extras/jena-querybuilder
deleted file mode 160000
index dc4dbdb..0000000
--- a/jena-extras/jena-querybuilder
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit dc4dbdb52854219a45fb9a4a8c51453e24054a08
diff --git a/jena-extras/jena-querybuilder/LICENSE b/jena-extras/jena-querybuilder/LICENSE
new file mode 100644
index 0000000..e06d208
--- /dev/null
+++ b/jena-extras/jena-querybuilder/LICENSE
@@ -0,0 +1,202 @@
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/jena-extras/jena-querybuilder/README.md b/jena-extras/jena-querybuilder/README.md
new file mode 100644
index 0000000..6e7ab47
--- /dev/null
+++ b/jena-extras/jena-querybuilder/README.md
@@ -0,0 +1,49 @@
+querybuilder
+============
+
+Query Builder for Jena.  Implementations of Ask, Construct and Select builders that allow developers to create queries without resorting to StringBuilders or similar solutions.
+
+Each of the builders has a series of methods to define the query.  Each method returns the builder for easy chaing.  The  example:
+
+```
+SelectBuilder sb = new SelectBuilder()
+  .addVar( "*" )
+  .addWhere( "?s", "?o", "?p" );
+  
+Query q = sb.build();
+
+```
+
+produces `SELECT * WHERE { ?s ?o ?p . }`
+
+Template Usage
+==============
+
+In addition to making it easier to build valid queries the QueryBuilder has a clone method.  Using this a developer can create as "Template" query and add to it as necessary.
+
+for example using the above query as the "template" the this code:
+
+```
+SelectBuilder sb2 = sb.clone();
+sb2.addPrefix( "foaf", "http://xmlns.com/foaf/0.1/" ).addWhere( ?s, RDF.type, foaf:Person) 
+```
+
+produces `PREFIX foaf: http://xmlns.com/foaf/0.1/ SELECT * WHERE { ?s ?o ?p . ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> foaf:person . }`
+
+Prepared Statement Usage
+========================
+
+The query builders have the ability to replace variables with other values.  This can be 
+
+```
+SelectBuilder sb = new SelectBuilder()
+  .addVar( "*" )
+  .addWhere( "?s", "?o", "?p" );
+  
+sb.setVar( Var.alloc( "?p" ), NodeFactory.createURI( "http://xmlns.com/foaf/0.1/Person" )
+Query q = sb.build();
+
+```
+
+produces `SELECT * WHERE { ?s ?o <http://xmlns.com/foaf/0.1/Person> . }`
+
diff --git a/jena-extras/jena-querybuilder/license-header.txt b/jena-extras/jena-querybuilder/license-header.txt
new file mode 100644
index 0000000..a9ac967
--- /dev/null
+++ b/jena-extras/jena-querybuilder/license-header.txt
@@ -0,0 +1,14 @@
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
diff --git a/jena-extras/jena-querybuilder/pom.xml b/jena-extras/jena-querybuilder/pom.xml
new file mode 100644
index 0000000..da311b5
--- /dev/null
+++ b/jena-extras/jena-querybuilder/pom.xml
@@ -0,0 +1,48 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>jena-querybuilder</artifactId>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.7</source>
+          <target>1.7</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+  	<dependency>
+  		<groupId>org.apache.jena</groupId>
+  		<artifactId>apache-jena-libs</artifactId>
+  		<type>pom</type>
+  	</dependency>
+  	<dependency>
+			<groupId>org.xenei</groupId>
+			<artifactId>junit-contracts</artifactId>
+		</dependency>
+  </dependencies>
+  <name>Apache Jena Query Builder- jena-querybulder</name>
+  <inceptionYear>2014</inceptionYear>
+  <organization>
+  	<name>The Apache Software Foundation</name>
+  	<url>http://www.apache.org/</url>
+  </organization>
+  <properties>
+  	
+  </properties>
+  <scm>
+ <!-- 	<url>https://svn.apache.org/repos/asf/jena/Experimental/jena-common/</url>
+  	<connection>scm:svn:https://svn.apache.org/repos/asf/jena/Experimental/jena-common/</connection>
+  	<developerConnection>scm:svn:https://svn.apache.org/repos/asf/jena/Experimental/jena-common/</developerConnection>
+  	-->
+  </scm>
+  <parent>
+  	<groupId>org.apache.jena</groupId>
+  	<artifactId>jena-extras</artifactId>
+  	<relativePath>..</relativePath>
+  	<version>2.12.2-SNAPSHOT</version>
+  </parent>
+  <description>A utility package to simplify the building of ARQ queries in code.  Provides both a simple builder interface for queries as well as simple prepared statement processing.</description>
+</project>
\ No newline at end of file
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java
new file mode 100644
index 0000000..baea059
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java
@@ -0,0 +1,362 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+
+import org.apache.jena.arq.querybuilder.clauses.ConstructClause;
+import org.apache.jena.arq.querybuilder.clauses.DatasetClause;
+import org.apache.jena.arq.querybuilder.clauses.PrologClause;
+import org.apache.jena.arq.querybuilder.clauses.SelectClause;
+import org.apache.jena.arq.querybuilder.clauses.SolutionModifierClause;
+import org.apache.jena.arq.querybuilder.clauses.WhereClause;
+import org.apache.jena.arq.querybuilder.handlers.ConstructHandler;
+import org.apache.jena.arq.querybuilder.handlers.DatasetHandler;
+import org.apache.jena.arq.querybuilder.handlers.Handler;
+import org.apache.jena.arq.querybuilder.handlers.PrologHandler;
+import org.apache.jena.arq.querybuilder.handlers.SelectHandler;
+import org.apache.jena.arq.querybuilder.handlers.SolutionModifierHandler;
+import org.apache.jena.arq.querybuilder.handlers.WhereHandler;
+import org.apache.jena.riot.RiotException;
+import org.apache.jena.riot.system.PrefixMapFactory;
+
+import com.hp.hpl.jena.graph.FrontsNode;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.graph.NodeFactory;
+import com.hp.hpl.jena.graph.impl.LiteralLabelFactory;
+import com.hp.hpl.jena.query.Query;
+import com.hp.hpl.jena.rdf.model.Resource;
+import com.hp.hpl.jena.sparql.ARQInternalErrorException;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.expr.ExprVar;
+import com.hp.hpl.jena.sparql.util.NodeFactoryExtra;
+
+/**
+ * Base class for all QueryBuilders.
+ * 
+ * @param <T>
+ *            The derived class type. Used for return types.
+ */
+public abstract class AbstractQueryBuilder<T extends AbstractQueryBuilder<T>>
+		implements Cloneable, PrologClause<T> {
+
+	// all queries have prologs
+	protected PrologHandler prologHandler;
+	// the query this builder is building
+	protected Query query;
+	// a map of vars to nodes for replacement during build.
+	private Map<Var, Node> values;
+
+	/**
+	 * Make a Node from an object.
+	 * <ul>
+	 * <li>Will return Node.ANY if object is null.</li>
+	 * <li>Will return the enclosed Node from a FrontsNode</li>
+	 * <li>Will return the object if it is a Node.</li>
+	 * <li>Will call NodeFactoryExtra.parseNode() using the currently defined
+	 * prefixes if the object is a String</li>
+	 * <li>Will create a literal representation if the parseNode() fails or for
+	 * any other object type.</li>
+	 * </ul>
+	 * 
+	 * @param o
+	 *            The object to convert. (may be null)
+	 * @return The Node value.
+	 */
+	public Node makeNode(Object o) {
+		if (o == null) {
+			return Node.ANY;
+		}
+		if (o instanceof FrontsNode) {
+			return ((FrontsNode) o).asNode();
+		}
+
+		if (o instanceof Node) {
+			return (Node) o;
+		}
+		if (o instanceof String) {
+			try {
+				return NodeFactoryExtra.parseNode((String) o, PrefixMapFactory
+						.createForInput(query.getPrefixMapping()));
+			} catch (RiotException e) {
+				// expected in some cases -- do nothing
+			}
+
+		}
+		return NodeFactory.createLiteral(LiteralLabelFactory.create(o));
+	}
+
+	/**
+	 * Make a Var from an object.
+	 * <ul>
+	 * <li>Will return Var.ANON if object is null.</li>
+	 * <li>Will return null if the object is "*" or Node_RuleVariable.WILD</li>
+	 * <li>Will return the object if it is a Var</li>
+	 * <li>Will return resolve FrontsNode to Node and then resolve to Var</li>
+	 * <li>Will return resolve Node if the Node implements Node_Variable,
+	 * otherwise throws an NotAVariableException (instance of
+	 * ARQInternalErrorException)</li>
+	 * <li>Will return ?x if object is "?x"</li>
+	 * <li>Will return ?x if object is "x"</li>
+	 * <li>Will return the enclosed Var of a ExprVar</li>
+	 * <li>For all other objects will return the "?" prefixed to the toString()
+	 * value.</li>
+	 * </ul>
+	 * 
+	 * @param o
+	 *            The object to convert.
+	 * @return the Var value.
+	 * @throws ARQInternalErrorException
+	 */
+	public Var makeVar(Object o) throws ARQInternalErrorException {
+		if (o == null) {
+			return Var.ANON;
+		}
+		if (o instanceof Var) {
+			return (Var) o;
+		}
+		Var retval = null;
+		if (o instanceof FrontsNode) {
+			retval = Var.alloc(((FrontsNode) o).asNode());
+		} else if (o instanceof Node) {
+			retval = Var.alloc((Node) o);
+		} else if (o instanceof ExprVar) {
+			retval = Var.alloc((ExprVar) o);
+		} else {
+			retval = Var.alloc(Var.canonical(o.toString()));
+		}
+		if ("*".equals(Var.canonical(retval.toString()))) {
+			return null;
+		}
+		return retval;
+	}
+
+	/**
+	 * Create a new query builder.
+	 */
+	protected AbstractQueryBuilder() {
+		query = new Query();
+		prologHandler = new PrologHandler(query);
+		values = new HashMap<Var, Node>();
+	}
+
+	/**
+	 * Set a variable replacement. During build all instances of var in the
+	 * query will be replaced with value. If value is null the replacement is
+	 * cleared.
+	 * 
+	 * @param var
+	 *            The variable to replace
+	 * @param value
+	 *            The value to replace it with or null to remove the
+	 *            replacement.
+	 */
+	public void setVar(Var var, Node value) {
+		if (value == null) {
+			values.remove(var);
+		} else {
+			values.put(var, value);
+		}
+	}
+
+	/**
+	 * Set a variable replacement. During build all instances of var in the
+	 * query will be replaced with value. If value is null the replacement is
+	 * cleared.
+	 * 
+	 * See {@link #makeVar} for conversion of the var param. See
+	 * {@link #makeNode} for conversion of the value param.
+	 * 
+	 * @param var
+	 *            The variable to replace.
+	 * @param value
+	 *            The value to replace it with or null to remove the
+	 *            replacement.
+	 */
+	public void setVar(Object var, Object value) {
+		if (value == null) {
+			setVar(makeVar(var), null);
+		} else {
+			setVar(makeVar(var), makeNode(value));
+		}
+	}
+
+	@Override
+	public PrologHandler getPrologHandler() {
+		return prologHandler;
+	}
+
+	@Override
+	public T addPrefix(String pfx, Resource uri) {
+		return addPrefix(pfx, uri.getURI());
+	}
+
+	@Override
+	public T addPrefix(String pfx, Node uri) {
+		return addPrefix(pfx, uri.getURI());
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public T addPrefix(String pfx, String uri) {
+		prologHandler.addPrefix(pfx, uri);
+		return (T) this;
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public T addPrefixes(Map<String, String> prefixes) {
+		prologHandler.addPrefixes(prefixes);
+		return (T) this;
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public T setBase(String base) {
+		prologHandler.setBase(base);
+		return (T) this;
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public T setBase(Object base) {
+		setBase(makeNode(base).getURI());
+		return (T) this;
+	}
+
+	@Override
+	public String toString() {
+		return buildString();
+	}
+
+	/**
+	 * Build the query as a string.
+	 * 
+	 * @return the string representation of the query.
+	 */
+	public final String buildString() {
+		return build().toString();
+	}
+
+	/**
+	 * Build the query. Performs the var replacements as specified by
+	 * setVar(var,node) calls.
+	 * 
+	 * @return The query.
+	 */
+	public final Query build() {
+		Query q = new Query();
+		try {
+			Field f = Query.class.getDeclaredField("queryType");
+			f.setAccessible(true);
+			f.set(q, query.getQueryType());
+		} catch (NoSuchFieldException e) {
+			throw new IllegalStateException(e.getMessage(), e);
+		} catch (SecurityException e) {
+			throw new IllegalStateException(e.getMessage(), e);
+		} catch (IllegalAccessException e) {
+			throw new IllegalStateException(e.getMessage(), e);
+		}
+		Stack<Handler> handlerStack = new Stack<Handler>();
+		PrologHandler ph = new PrologHandler(q);
+		handlerStack.push(ph);
+		ph.addAll(prologHandler);
+		ph.setVars(values);
+		if (this instanceof SelectClause) {
+			SelectHandler sh = new SelectHandler(q);
+			sh.addAll(((SelectClause<?>) this).getSelectHandler());
+			sh.setVars(values);
+			handlerStack.push(sh);
+		}
+		if (this instanceof ConstructClause) {
+			ConstructHandler ch = new ConstructHandler(q);
+			ch.addAll(((ConstructClause<?>) this).getConstructHandler());
+			ch.setVars(values);
+			handlerStack.push(ch);
+		}
+		if (this instanceof DatasetClause) {
+			DatasetHandler dh = new DatasetHandler(q);
+			dh.addAll(((DatasetClause<?>) this).getDatasetHandler());
+			dh.setVars(values);
+			handlerStack.push(dh);
+		}
+		if (this instanceof SolutionModifierClause) {
+			SolutionModifierHandler smh = new SolutionModifierHandler(q);
+			smh.addAll(((SolutionModifierClause<?>) this)
+					.getSolutionModifierHandler());
+			smh.setVars(values);
+			handlerStack.push(smh);
+		}
+		if (this instanceof WhereClause) {
+			WhereHandler wh = new WhereHandler(q);
+			wh.addAll(((WhereClause<?>) this).getWhereHandler());
+			wh.setVars(values);
+			handlerStack.push(wh);
+		}
+
+		while (!handlerStack.isEmpty()) {
+			handlerStack.pop().build();
+		}
+
+		return q;
+	}
+
+	/**
+	 * Close the query.
+	 * 
+	 * This can be used when the query would not normally parse as is required
+	 * by the Query.clone() method.
+	 * 
+	 * @param q2
+	 *            The query to clone
+	 * @return A clone of the q2 param.
+	 */
+	public static Query clone(Query q2) {
+		Query retval = new Query();
+		new PrologHandler(retval).addAll(new PrologHandler(q2));
+		new ConstructHandler(retval).addAll(new ConstructHandler(q2));
+		new DatasetHandler(retval).addAll(new DatasetHandler(q2));
+		new SolutionModifierHandler(retval).addAll(new SolutionModifierHandler(
+				q2));
+		new WhereHandler(retval).addAll(new WhereHandler(q2));
+		new SelectHandler(retval).addAll(new SelectHandler(q2));
+		return retval;
+	}
+
+	/**
+	 * Rewrite a query replacing variables as specified in the values map.
+	 * 
+	 * @param q2
+	 *            The query to rewrite
+	 * @param values
+	 *            a Mapping of var to node for replacement.
+	 * @return The new query with the specified vars replaced.
+	 */
+	public static Query rewrite(Query q2, Map<Var, Node> values) {
+		new PrologHandler(q2).setVars(values);
+		new ConstructHandler(q2).setVars(values);
+		new DatasetHandler(q2).setVars(values);
+		new SolutionModifierHandler(q2).setVars(values);
+		new WhereHandler(q2).setVars(values);
+		new SelectHandler(q2).setVars(values);
+		return q2;
+	}
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AskBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AskBuilder.java
new file mode 100644
index 0000000..edb6885
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AskBuilder.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder;
+
+import java.util.Collection;
+
+import org.apache.jena.arq.querybuilder.clauses.DatasetClause;
+import org.apache.jena.arq.querybuilder.clauses.SolutionModifierClause;
+import org.apache.jena.arq.querybuilder.clauses.WhereClause;
+import org.apache.jena.arq.querybuilder.handlers.DatasetHandler;
+import org.apache.jena.arq.querybuilder.handlers.SolutionModifierHandler;
+import org.apache.jena.arq.querybuilder.handlers.WhereHandler;
+
+import com.hp.hpl.jena.graph.FrontsTriple;
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
+
+/**
+ * Build an ASK query.
+ * 
+ */
+public class AskBuilder extends AbstractQueryBuilder<AskBuilder> implements
+		DatasetClause<AskBuilder>, WhereClause<AskBuilder>,
+		SolutionModifierClause<AskBuilder> {
+	// the dataset handler
+	private final DatasetHandler datasetHandler;
+	// the where handler.
+	private final WhereHandler whereHandler;
+	// the solution modifier handler.
+	private final SolutionModifierHandler solutionModifier;
+
+	/**
+	 * The constructor
+	 */
+	public AskBuilder() {
+		super();
+		query.setQueryAskType();
+		datasetHandler = new DatasetHandler(query);
+		whereHandler = new WhereHandler(query);
+		solutionModifier = new SolutionModifierHandler(query);
+	}
+
+	@Override
+	public DatasetHandler getDatasetHandler() {
+		return datasetHandler;
+	}
+
+	@Override
+	public WhereHandler getWhereHandler() {
+		return whereHandler;
+	}
+
+	@Override
+	public AskBuilder clone() {
+		AskBuilder qb = new AskBuilder();
+		qb.prologHandler.addAll(prologHandler);
+		qb.datasetHandler.addAll(datasetHandler);
+		qb.solutionModifier.addAll(solutionModifier);
+		return qb;
+	}
+
+	@Override
+	public AskBuilder fromNamed(String graphName) {
+		datasetHandler.fromNamed(graphName);
+		return this;
+	}
+
+	@Override
+	public AskBuilder fromNamed(Collection<String> graphNames) {
+		datasetHandler.fromNamed(graphNames);
+		return this;
+	}
+
+	@Override
+	public AskBuilder from(String graphName) {
+		datasetHandler.from(graphName);
+		return this;
+	}
+
+	@Override
+	public AskBuilder from(Collection<String> graphName) {
+		datasetHandler.from(graphName);
+		return this;
+	}
+
+	@Override
+	public AskBuilder addWhere(Triple t) {
+		whereHandler.addWhere(t);
+		return this;
+	}
+
+	@Override
+	public AskBuilder addWhere(FrontsTriple t) {
+		whereHandler.addWhere(t.asTriple());
+		return this;
+	}
+
+	@Override
+	public AskBuilder addWhere(Object s, Object p, Object o) {
+		addWhere(new Triple(makeNode(s), makeNode(p), makeNode(o)));
+		return this;
+	}
+
+	@Override
+	public AskBuilder addOptional(Triple t) {
+		whereHandler.addOptional(t);
+		return this;
+	}
+
+	@Override
+	public AskBuilder addOptional(FrontsTriple t) {
+		whereHandler.addOptional(t.asTriple());
+		return this;
+	}
+
+	@Override
+	public AskBuilder addOptional(Object s, Object p, Object o) {
+		addOptional(new Triple(makeNode(s), makeNode(p), makeNode(o)));
+		return this;
+	}
+
+	@Override
+	public AskBuilder addFilter(String s) throws ParseException {
+		whereHandler.addFilter(s);
+		return this;
+	}
+
+	@Override
+	public AskBuilder addSubQuery(SelectBuilder subQuery) {
+		prologHandler.addAll(subQuery.getPrologHandler());
+		whereHandler.addSubQuery(subQuery);
+		return this;
+	}
+
+	@Override
+	public AskBuilder addUnion(SelectBuilder subQuery) {
+		whereHandler.addUnion(subQuery);
+		return this;
+	}
+
+	@Override
+	public AskBuilder addGraph(Object graph, SelectBuilder subQuery) {
+		prologHandler.addAll(subQuery.getPrologHandler());
+		whereHandler.addGraph(makeNode(graph), subQuery.getWhereHandler());
+		return this;
+	}
+
+	@Override
+	public AskBuilder addOrderBy(String orderBy) {
+		solutionModifier.addOrderBy(orderBy);
+		return this;
+	}
+
+	@Override
+	public AskBuilder addGroupBy(String groupBy) {
+		solutionModifier.addGroupBy(groupBy);
+		return this;
+	}
+
+	@Override
+	public AskBuilder addHaving(String having) throws ParseException {
+		solutionModifier.addHaving(having);
+		return this;
+	}
+
+	@Override
+	public AskBuilder setLimit(int limit) {
+		solutionModifier.setLimit(limit);
+		return this;
+	}
+
+	@Override
+	public AskBuilder setOffset(int offset) {
+		solutionModifier.setOffset(offset);
+		return this;
+	}
+
+	@Override
+	public SolutionModifierHandler getSolutionModifierHandler() {
+		return solutionModifier;
+	}
+
+}
\ No newline at end of file
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/ConstructBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/ConstructBuilder.java
new file mode 100644
index 0000000..eddc764
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/ConstructBuilder.java
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder;
+
+import java.util.Collection;
+
+import org.apache.jena.arq.querybuilder.clauses.ConstructClause;
+import org.apache.jena.arq.querybuilder.clauses.DatasetClause;
+import org.apache.jena.arq.querybuilder.clauses.SolutionModifierClause;
+import org.apache.jena.arq.querybuilder.clauses.WhereClause;
+import org.apache.jena.arq.querybuilder.handlers.ConstructHandler;
+import org.apache.jena.arq.querybuilder.handlers.DatasetHandler;
+import org.apache.jena.arq.querybuilder.handlers.SolutionModifierHandler;
+import org.apache.jena.arq.querybuilder.handlers.WhereHandler;
+
+import com.hp.hpl.jena.graph.FrontsTriple;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
+
+/**
+ * Build an Construct query.
+ * 
+ */
+public class ConstructBuilder extends AbstractQueryBuilder<ConstructBuilder>
+		implements DatasetClause<ConstructBuilder>,
+		WhereClause<ConstructBuilder>,
+		SolutionModifierClause<ConstructBuilder>,
+		ConstructClause<ConstructBuilder> {
+
+	// the handlers used by this builder
+	private final DatasetHandler datasetHandler;
+	private final WhereHandler whereHandler;
+	private final SolutionModifierHandler solutionModifier;
+	private final ConstructHandler constructHandler;
+
+	/**
+	 * Constructor
+	 */
+	public ConstructBuilder() {
+		super();
+		query.setQueryConstructType();
+		datasetHandler = new DatasetHandler(query);
+		whereHandler = new WhereHandler(query);
+		solutionModifier = new SolutionModifierHandler(query);
+		constructHandler = new ConstructHandler(query);
+	}
+
+	@Override
+	public DatasetHandler getDatasetHandler() {
+		return datasetHandler;
+	}
+
+	@Override
+	public WhereHandler getWhereHandler() {
+		return whereHandler;
+	}
+
+	@Override
+	public ConstructHandler getConstructHandler() {
+		return constructHandler;
+	}
+
+	@Override
+	public SolutionModifierHandler getSolutionModifierHandler() {
+		return solutionModifier;
+	}
+
+	@Override
+	public ConstructBuilder clone() {
+		ConstructBuilder qb = new ConstructBuilder();
+		qb.prologHandler.addAll(prologHandler);
+		qb.datasetHandler.addAll(datasetHandler);
+		qb.whereHandler.addAll(whereHandler);
+		qb.solutionModifier.addAll(solutionModifier);
+		qb.constructHandler.addAll(constructHandler);
+		return qb;
+	}
+
+	@Override
+	public ConstructBuilder fromNamed(String graphName) {
+		datasetHandler.fromNamed(graphName);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder fromNamed(Collection<String> graphNames) {
+		datasetHandler.fromNamed(graphNames);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder from(String graphName) {
+		datasetHandler.from(graphName);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder from(Collection<String> graphName) {
+		datasetHandler.from(graphName);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addOrderBy(String orderBy) {
+		solutionModifier.addOrderBy(orderBy);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addGroupBy(String groupBy) {
+		solutionModifier.addGroupBy(groupBy);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addHaving(String having) throws ParseException {
+		solutionModifier.addHaving(having);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder setLimit(int limit) {
+		solutionModifier.setLimit(limit);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder setOffset(int offset) {
+		solutionModifier.setOffset(offset);
+		return this;
+	}
+
+	// convert a node to a string
+	private static String toString(Node node) {
+		if (node.isBlank()) {
+			return node.getBlankNodeLabel();
+		}
+		if (node.isLiteral()) {
+			return node.toString();
+		}
+		if (node.isURI()) {
+			return String.format("<%s>", node.getURI());
+		}
+		if (node.isVariable()) {
+			return String.format("?%s", node.getName());
+		}
+		return node.toString();
+	}
+
+	@Override
+	public ConstructBuilder addWhere(Triple t) {
+		whereHandler.addWhere(t);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addWhere(FrontsTriple t) {
+		whereHandler.addWhere(t.asTriple());
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addWhere(Object s, Object p, Object o) {
+		addWhere(new Triple(makeNode(s), makeNode(p), makeNode(o)));
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addOptional(Triple t) {
+		whereHandler.addOptional(t);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addOptional(FrontsTriple t) {
+		whereHandler.addOptional(t.asTriple());
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addOptional(Object s, Object p, Object o) {
+		addOptional(new Triple(makeNode(s), makeNode(p), makeNode(o)));
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addFilter(String s) throws ParseException {
+		whereHandler.addFilter(s);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addSubQuery(SelectBuilder subQuery) {
+		prologHandler.addAll(subQuery.prologHandler);
+		whereHandler.addSubQuery(subQuery);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addUnion(SelectBuilder subQuery) {
+		whereHandler.addUnion(subQuery);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addGraph(Object graph, SelectBuilder subQuery) {
+		prologHandler.addAll(subQuery.prologHandler);
+		whereHandler.addGraph(makeNode(graph), subQuery.getWhereHandler());
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addConstruct(Triple t) {
+		constructHandler.addConstruct(t);
+		return this;
+	}
+
+	@Override
+	public ConstructBuilder addConstruct(FrontsTriple t) {
+		return addConstruct(t.asTriple());
+	}
+
+	@Override
+	public ConstructBuilder addConstruct(Object s, Object p, Object o) {
+		return addConstruct(new Triple(makeNode(s), makeNode(p), makeNode(o)));
+	}
+
+}
\ No newline at end of file
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/SelectBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/SelectBuilder.java
new file mode 100644
index 0000000..30b5ab0
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/SelectBuilder.java
@@ -0,0 +1,281 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder;
+
+import java.util.Collection;
+import java.util.List;
+import org.apache.jena.arq.querybuilder.clauses.DatasetClause;
+import org.apache.jena.arq.querybuilder.clauses.SelectClause;
+import org.apache.jena.arq.querybuilder.clauses.SolutionModifierClause;
+import org.apache.jena.arq.querybuilder.clauses.WhereClause;
+import org.apache.jena.arq.querybuilder.handlers.DatasetHandler;
+import org.apache.jena.arq.querybuilder.handlers.SelectHandler;
+import org.apache.jena.arq.querybuilder.handlers.SolutionModifierHandler;
+import org.apache.jena.arq.querybuilder.handlers.WhereHandler;
+
+import com.hp.hpl.jena.graph.FrontsNode;
+import com.hp.hpl.jena.graph.FrontsTriple;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
+
+/**
+ * Build a select query.
+ *
+ */
+public class SelectBuilder extends AbstractQueryBuilder<SelectBuilder>
+		implements DatasetClause<SelectBuilder>, WhereClause<SelectBuilder>,
+		SolutionModifierClause<SelectBuilder>, SelectClause<SelectBuilder> {
+
+	// the handlers.
+	private DatasetHandler datasetHandler;
+	private WhereHandler whereHandler;
+	private SolutionModifierHandler solutionModifier;
+	private SelectHandler selectHandler;
+
+	/**
+	 * Constructor.
+	 */
+	public SelectBuilder() {
+		super();
+		query.setQuerySelectType();
+		datasetHandler = new DatasetHandler(query);
+		whereHandler = new WhereHandler(query);
+		solutionModifier = new SolutionModifierHandler(query);
+		selectHandler = new SelectHandler(query);
+	}
+
+	@Override
+	public DatasetHandler getDatasetHandler() {
+		return datasetHandler;
+	}
+
+	@Override
+	public WhereHandler getWhereHandler() {
+		return whereHandler;
+	}
+
+	@Override
+	public SelectBuilder clone() {
+		SelectBuilder qb = new SelectBuilder();
+		qb.prologHandler.addAll(prologHandler);
+		qb.datasetHandler.addAll(datasetHandler);
+		qb.whereHandler.addAll(whereHandler);
+		qb.solutionModifier.addAll(solutionModifier);
+		qb.selectHandler.addAll(selectHandler);
+
+		return qb;
+	}
+
+	@Override
+	public SelectBuilder setDistinct(boolean state) {
+		selectHandler.setDistinct(state);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder setReduced(boolean state) {
+		selectHandler.setReduced(state);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addVar(Object var) {
+		selectHandler.addVar(makeVar(var));
+		return this;
+	}
+
+	@Override
+	public List<Var> getVars() {
+		return selectHandler.getVars();
+	}
+
+	@Override
+	public SelectBuilder fromNamed(String graphName) {
+		datasetHandler.fromNamed(graphName);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder fromNamed(Collection<String> graphNames) {
+		datasetHandler.fromNamed(graphNames);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder from(String graphName) {
+		datasetHandler.from(graphName);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder from(Collection<String> graphName) {
+		datasetHandler.from(graphName);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addOrderBy(String orderBy) {
+		solutionModifier.addOrderBy(orderBy);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addGroupBy(String groupBy) {
+		solutionModifier.addGroupBy(groupBy);
+		return this;
+	}
+
+	@Override
+	public SolutionModifierHandler getSolutionModifierHandler() {
+		return solutionModifier;
+	}
+
+	@Override
+	public SelectBuilder addHaving(String having) throws ParseException {
+		solutionModifier.addHaving(having);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder setLimit(int limit) {
+		solutionModifier.setLimit(limit);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder setOffset(int offset) {
+		solutionModifier.setOffset(offset);
+		return this;
+	}
+
+	/**
+	 * Convert a node to a string.
+	 * If the node is a literal return the literal value.
+	 * If the node is a URI return the URI enclosed with &lt; and &gt;
+	 * If the node is a variable return the name preceeded by '?'
+	 * @param node The node to convert.
+	 * @return A string representation of the node.
+	 */
+	private static String toString(Node node) {
+		if (node.isBlank()) {
+			return node.getBlankNodeLabel();
+		}
+		if (node.isLiteral()) {
+			return node.toString();
+		}
+		if (node.isURI()) {
+			return String.format("<%s>", node.getURI());
+		}
+		if (node.isVariable()) {
+			return String.format("?%s", node.getName());
+		}
+		return node.toString();
+	}
+
+	/**
+	 * Convert the object to a string.
+	 * If the object is a node or fronts a node then 
+	 * <ul>
+	 * <li>If the node is a literal return the literal value.</li>
+	 * <li>If the node is a URI return the URI enclosed with &lt; and &gt;</li>
+	 * <li>If the node is a variable return the name preceeded by '?'</li>
+	 * </ul>
+	 * otherwise return the toString() method of the object.
+	 * @param o the Object to convert.
+	 * @return The string representation of the object.
+	 */
+	public static String makeString(Object o) {
+		if (o instanceof FrontsNode) {
+			return toString(((FrontsNode) o).asNode());
+		}
+		if (o instanceof Node) {
+			return toString((Node) o);
+		}
+		return o.toString();
+	}
+
+	@Override
+	public SelectBuilder addWhere(Triple t) {
+		whereHandler.addWhere(t);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addWhere(FrontsTriple t) {
+		whereHandler.addWhere(t.asTriple());
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addWhere(Object s, Object p, Object o) {
+		addWhere(new Triple(makeNode(s), makeNode(p), makeNode(o)));
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addOptional(Triple t) {
+		whereHandler.addOptional(t);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addOptional(FrontsTriple t) {
+		whereHandler.addOptional(t.asTriple());
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addOptional(Object s, Object p, Object o) {
+		addOptional(new Triple(makeNode(s), makeNode(p), makeNode(o)));
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addFilter(String s) throws ParseException {
+		whereHandler.addFilter(s);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addSubQuery(SelectBuilder subQuery) {
+		prologHandler.addAll(subQuery.prologHandler);
+		whereHandler.addSubQuery(subQuery);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addUnion(SelectBuilder subQuery) {
+		whereHandler.addUnion(subQuery);
+		return this;
+	}
+
+	@Override
+	public SelectBuilder addGraph(Object graph, SelectBuilder subQuery) {
+		prologHandler.addAll(subQuery.prologHandler);
+		whereHandler.addGraph(makeNode(graph), subQuery.whereHandler);
+		return this;
+	}
+
+	@Override
+	public SelectHandler getSelectHandler() {
+		return selectHandler;
+	}
+
+}
\ No newline at end of file
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/ConstructClause.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/ConstructClause.java
new file mode 100644
index 0000000..285fc92
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/ConstructClause.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.clauses;
+
+import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
+import org.apache.jena.arq.querybuilder.handlers.ConstructHandler;
+
+import com.hp.hpl.jena.graph.FrontsTriple;
+import com.hp.hpl.jena.graph.Triple;
+
+/**
+ * Interface that defines the ConstructClause as per
+ * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rConstructTemplate
+ * 
+ * @param <T>
+ *            The Builder type that the clause is part of.
+ */
+public interface ConstructClause<T extends AbstractQueryBuilder<T>> {
+
+	/**
+	 * Add a construct triple.
+	 * 
+	 * @param t
+	 *            The triple to add.
+	 * @return The builder for chaining.
+	 */
+	public T addConstruct(Triple t);
+
+	/**
+	 * Add a construct triple.
+	 * 
+	 * @param t
+	 *            The triple to add.
+	 * @return The builder for chaining.
+	 */
+	public T addConstruct(FrontsTriple t);
+
+	/**
+	 * Add a construct triple.
+	 * 
+	 * See {@link AbstractQueryBuilder#makeNode} for conversion of the param values.
+	 * 
+	 * @param s
+	 *            The subject of the triple,
+	 * @param p
+	 *            The predicate of the triple.
+	 * @param o
+	 *            The object of the triple.
+	 * @return the builder for chaining.
+	 */
+	public T addConstruct(Object s, Object p, Object o);
+
+	/**
+	 * Get the Construct handler for this construct clause.
+	 * @return the construct handler used by this builder.
+	 */
+	public ConstructHandler getConstructHandler();
+
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/DatasetClause.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/DatasetClause.java
new file mode 100644
index 0000000..faa51c0
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/DatasetClause.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.clauses;
+
+import java.util.Collection;
+
+import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
+import org.apache.jena.arq.querybuilder.handlers.DatasetHandler;
+
+/**
+ * Interface that defines the DatasetClause as per
+ * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rDatasetClause
+ * 
+ * @param <T>
+ *            The Builder type that the clause is part of.
+ */
+public interface DatasetClause<T extends AbstractQueryBuilder<T>> {
+	/**
+	 * Add the "FROM NAMED" graph name.
+	 * 
+	 * @param graphName
+	 *            the graph name to add.
+	 * @return The builder for chaining.
+	 */
+	public T fromNamed(String graphName);
+
+	/**
+	 * Add several "FROM NAMED" graph names.
+	 * 
+	 * @param graphNames
+	 *            the collection graph names to add.
+	 * @return The builder for chaining.
+	 */
+	public T fromNamed(Collection<String> graphNames);
+
+	/**
+	 * Add the "FROM" graph name.
+	 * 
+	 * @param graphName
+	 *            the graph name to add.
+	 * @return The builder for chaining.
+	 */
+	public T from(String graphName);
+
+	/**
+	 * Add several "FROM" graph names.
+	 * 
+	 * @param graphName
+	 *            the collection graph names to add.
+	 * @return The builder for chaining.
+	 */
+	public T from(Collection<String> graphName);
+
+	/**
+	 * Get the Dataset handler for this clause.
+	 * @return The DatasetHandler this clause is using.
+	 */
+	public DatasetHandler getDatasetHandler();
+
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/PrologClause.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/PrologClause.java
new file mode 100644
index 0000000..8f69598
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/PrologClause.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.clauses;
+
+import java.util.Map;
+
+import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
+import org.apache.jena.arq.querybuilder.handlers.PrologHandler;
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.rdf.model.Resource;
+
+/**
+ * Interface that defines the PrologClause as per
+ * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rPrologue
+ * 
+ * @param <T>
+ *            The Builder type that the clause is part of.
+ */
+public interface PrologClause<T extends AbstractQueryBuilder<T>> {
+	/**
+	 * Get the prolog handler for this clause. 
+	 * @return The PrologHandler this clause is using.
+	 */
+	public PrologHandler getPrologHandler();
+
+	/**
+	 * Add a prefix.
+	 * 
+	 * @param pfx
+	 *            The prefix.
+	 * @param uri
+	 *            The URI for the prefix
+	 * @return The builder for chaining.
+	 */
+	public T addPrefix(String pfx, Resource uri);
+
+	/**
+	 * Add a prefix.
+	 * 
+	 * @param pfx
+	 *            The prefix.
+	 * @param uri
+	 *            The URI for the prefix
+	 * @return The builder for chaining.
+	 */
+	public T addPrefix(String pfx, Node uri);
+
+	/**
+	 * Add a prefix.
+	 * 
+	 * @param pfx
+	 *            The prefix.
+	 * @param uri
+	 *            The URI for the prefix
+	 * @return The builder for chaining.
+	 */
+	public T addPrefix(String pfx, String uri);
+
+	/**
+	 * Add a prefix.
+	 * 
+	 * @param prefixes
+	 *            A mapping of prefix to URI to add.
+	 * @return The builder for chaining.
+	 */
+	public T addPrefixes(Map<String, String> prefixes);
+
+	/**
+	 * Set the base URI.
+	 * 
+	 * See {@link AbstractQueryBuilder#makeNode} for conversion of the uri param. The resulting Node
+	 * must be a URI.
+	 * 
+	 * @param uri
+	 *            The base URI to use.
+	 * @return The builder for chaining.
+	 */
+	public T setBase(Object uri);
+
+	/**
+	 * Set the base URI.
+	 * 
+	 * @param uri
+	 *            The base URI to use.
+	 * @return The builder for chaining.
+	 */
+	public T setBase(String uri);
+
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/SelectClause.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/SelectClause.java
new file mode 100644
index 0000000..2d29010
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/SelectClause.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.clauses;
+
+import java.util.List;
+import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
+import org.apache.jena.arq.querybuilder.handlers.SelectHandler;
+
+import com.hp.hpl.jena.sparql.core.Var;
+
+/**
+ * Interface that defines the SelectClause as per
+ * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rSelectClause
+ * 
+ * @param <T>
+ *            The Builder type that the clause is part of.
+ */
+public interface SelectClause<T extends AbstractQueryBuilder<T>> {
+	/**
+	 * Get the select handler for this clause
+	 * @return The SelectHandler that the clause is using
+	 */
+	public SelectHandler getSelectHandler();
+
+	/**
+	 * Set set the distinct flag.
+	 * 
+	 * Setting the select distinct will unset reduced if it was set.
+	 * 
+	 * @param state
+	 *            if true results will be distinct.
+	 * @return The builder for chaining.
+	 */
+	public T setDistinct(boolean state);
+
+	/**
+	 * Set set the reduced flag.
+	 * 
+	 * Setting the select reduced will unset distinct if it was set.
+	 * 
+	 * @param state
+	 *            if true results will be reduced.
+	 * @return The builder for chaining.
+	 */
+	public T setReduced(boolean state);
+
+	/**
+	 * Add a variable to the select statement.
+	 * 
+	 * A variable may only be added once. Attempting to add the same variable
+	 * multiple times will be silently ignored.
+	 * 
+	 * @param var
+	 *            The variable to add.
+	 * @return The builder for chaining.
+	 */
+	public T addVar(Object var);
+
+	/**
+	 * @return A list of all the variables that have been added.
+	 */
+	public List<Var> getVars();
+
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/SolutionModifierClause.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/SolutionModifierClause.java
new file mode 100644
index 0000000..3be18a0
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/SolutionModifierClause.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.clauses;
+
+import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
+import org.apache.jena.arq.querybuilder.handlers.SolutionModifierHandler;
+
+import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
+
+/**
+ * Interface that defines the SolutionClause as per
+ * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rSolutionModifier
+ * 
+ * @param <T>
+ *            The Builder type that the clause is part of.
+ */
+public interface SolutionModifierClause<T extends AbstractQueryBuilder<T>> {
+
+	/**
+	 * Add an order by
+	 * 
+	 * @param orderBy
+	 *            The variable name to order by.
+	 * @return The builder for chaining.
+	 */
+	public T addOrderBy(String orderBy);
+
+	/**
+	 * Add a group by
+	 * 
+	 * @param groupBy
+	 *            The variable name to group by.
+	 * @return The builder for chaining.
+	 */
+	public T addGroupBy(String groupBy);
+
+	/**
+	 * Add a having expression.
+	 * 
+	 * @param expression
+	 *            Expression to evaluate for the having.
+	 * @return The builder for chaining.
+	 */
+	public T addHaving(String expression) throws ParseException;
+
+	/**
+	 * Set the limit.
+	 * 
+	 * Setting the limit to 0 (zero) sets no limit.
+	 * 
+	 * @param limit
+	 *            the maximum number of results to return.
+	 * @return The builder for chaining.
+	 */
+	public T setLimit(int limit);
+
+	/**
+	 * Set the offset.
+	 * 
+	 * Setting the offset to 0 (zero) sets no offset.
+	 * 
+	 * @param offset
+	 *            the number of results to skip before returning results..
+	 * @return The builder for chaining.
+	 */
+	public T setOffset(int offset);
+
+	/**
+	 * Get the Solution modifier for this clause.
+	 * @return The SolutionModifierHandler the clause is using.
+	 */
+	public SolutionModifierHandler getSolutionModifierHandler();
+
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/WhereClause.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/WhereClause.java
new file mode 100644
index 0000000..9f92941
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/WhereClause.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.clauses;
+
+import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
+import org.apache.jena.arq.querybuilder.SelectBuilder;
+import org.apache.jena.arq.querybuilder.handlers.WhereHandler;
+
+import com.hp.hpl.jena.graph.FrontsTriple;
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
+
+/**
+ * Interface that defines the WhereClause as per
+ * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rWhereClause
+ * 
+ * @param <T>
+ *            The Builder type that the clause is part of.
+ */
+public interface WhereClause<T extends AbstractQueryBuilder<T>> {
+
+	/**
+	 * Adds a triple as to the where clause.
+	 * 
+	 * @param t
+	 *            The triple to add
+	 * @return The Builder for chaining.
+	 */
+	public T addWhere(Triple t);
+
+	/**
+	 * Adds a triple as to the where clause.
+	 * 
+	 * @param t
+	 *            The triple to add
+	 * @return The Builder for chaining.
+	 */
+	public T addWhere(FrontsTriple t);
+
+	/**
+	 * Adds a triple to the where clause.
+	 * 
+	 * See {@link AbstractQueryBuilder#makeNode} for conversion of the param values.
+	 * 
+	 * @param s
+	 *            The subject.
+	 * @param p
+	 *            The predicate.
+	 * @param o
+	 *            The object.
+	 * @return The Builder for chaining.
+	 */
+	public T addWhere(Object s, Object p, Object o);
+
+	/**
+	 * Adds an optional triple as to the where clause.
+	 * 
+	 * @param t
+	 *            The triple to add
+	 * @return The Builder for chaining.
+	 */
+	public T addOptional(Triple t);
+
+	/**
+	 * Adds an optional triple as to the where clause.
+	 * 
+	 * @param t
+	 *            The triple to add
+	 * @return The Builder for chaining.
+	 */
+	public T addOptional(FrontsTriple t);
+
+	/**
+	 * Adds an optional triple to the where clause.
+	 * 
+	 * See {@link AbstractQueryBuilder#makeNode} for conversion of the param values.
+	 * 
+	 * @param s
+	 *            The subject.
+	 * @param p
+	 *            The predicate.
+	 * @param o
+	 *            The object.
+	 * @return The Builder for chaining.
+	 */
+	public T addOptional(Object s, Object p, Object o);
+
+	/**
+	 * Adds a filter to the where clause
+	 * 
+	 * @param expression
+	 *            the expression to evaluate for the filter.
+	 * @return @return The Builder for chaining.
+	 * @throws ParseException
+	 *             If the expression can not be parsed.
+	 */
+	public T addFilter(String expression) throws ParseException;
+
+	/**
+	 * Add a sub query.
+	 * 
+	 * @param subQuery
+	 *            The subquery as defined by a SelectBuilder.
+	 * @return This builder for chaining.
+	 */
+	public T addSubQuery(SelectBuilder subQuery);
+
+	/**
+	 * Add a union.
+	 * 
+	 * @param union
+	 *            The union as defined by a SelectBuilder.
+	 * @return This builder for chaining.
+	 */
+	public T addUnion(SelectBuilder union);
+
+	/**
+	 * Add a graph statement to the query as per
+	 * http://www.w3.org/TR/2013/REC-sparql11
+	 * -query-20130321/#rGraphGraphPattern.
+	 * 
+	 * See {@link AbstractQueryBuilder#makeNode} for conversion of the graph param.
+	 * 
+	 * @param graph
+	 *            The iri or variable identifying the graph.
+	 * @param subQuery
+	 *            The graph to add.
+	 * @return This builder for chaining.
+	 */
+	public T addGraph(Object graph, SelectBuilder subQuery);
+
+	/**
+	 * Get the Where handler for this clause.
+	 * @return The WhereHandler used by this clause.
+	 */
+	public WhereHandler getWhereHandler();
+
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/package-info.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/package-info.java
new file mode 100644
index 0000000..e98871a
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * Interfaces that describe various SPARQL clauses as per
+ * http://www.w3.org/TR/2013/REC-sparql11-query-20130321.
+ * 
+ * These classes are used to compose consistent interfaces for specific builder implementations. 
+ */
+package org.apache.jena.arq.querybuilder.clauses;
\ No newline at end of file
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/ConstructHandler.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/ConstructHandler.java
new file mode 100644
index 0000000..55f1794
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/ConstructHandler.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.handlers;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.jena.arq.querybuilder.rewriters.AbstractRewriter;
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.query.Query;
+import com.hp.hpl.jena.sparql.core.BasicPattern;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.syntax.Template;
+
+/**
+ * The handler for construct clauses.
+ *
+ */
+public class ConstructHandler implements Handler {
+	private final Query query;
+	private List<Triple> constructs;
+
+	/**
+	 * The constructor
+	 * @param query The query that this handler will be modifying.
+	 */
+	public ConstructHandler(Query query) {
+		this.query = query;
+		constructs = new ArrayList<Triple>();
+		if (query.getConstructTemplate() != null) {
+			for (Triple t : query.getConstructTemplate().getTriples()) {
+				constructs.add(t);
+			}
+		}
+	}
+
+	/**
+	 * Add a triple to the construct statement.
+	 * @param t The triple to add.
+	 */
+	public void addConstruct(Triple t) {
+		constructs.add(t);
+		query.setConstructTemplate(new Template(BasicPattern.wrap(constructs)));
+	}
+
+	/**
+	 * Add all the construct handlers from the handler argument to this construct.
+	 * @param handler The construct handler to copy from.
+	 */
+	public void addAll(ConstructHandler handler) {
+		constructs.addAll(handler.constructs);
+		query.setConstructTemplate(new Template(BasicPattern.wrap(constructs)));
+	}
+
+	@Override
+	public void setVars(Map<Var, Node> values) {
+		if (values.isEmpty()) {
+			return;
+		}
+		AbstractRewriter<Node> rw = new AbstractRewriter<Node>(values) {
+		};
+		query.setConstructTemplate(new Template(BasicPattern.wrap(rw
+				.rewrite(constructs))));
+	}
+
+	@Override
+	public void build() {
+		// there are no special operations for the build.
+	}
+
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/DatasetHandler.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/DatasetHandler.java
new file mode 100644
index 0000000..e829e56
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/DatasetHandler.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.handlers;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.query.Query;
+import com.hp.hpl.jena.sparql.core.Var;
+
+/**
+ * Handler for a dataset.
+ *
+ */
+public class DatasetHandler implements Handler {
+
+	// the query to manage
+	private final Query query;
+
+	/**
+	 * Constructor.
+	 * @param query The query the handler will manage.
+	 */
+	public DatasetHandler(Query query) {
+		this.query = query;
+	}
+
+	/**
+	 * Add all the dataset information from the handler argument.
+	 * @param datasetHandler The handler to copy from.
+	 */
+	public void addAll(DatasetHandler datasetHandler) {
+		from(datasetHandler.query.getGraphURIs());
+		fromNamed(datasetHandler.query.getNamedGraphURIs());
+	}
+
+	/**
+	 * Add a graph name to the from named list.
+	 * @param graphName The graph name to add.
+	 */
+	public void fromNamed(String graphName) {
+		query.addNamedGraphURI(graphName);
+	}
+
+	/**
+	 * Add the graph names to the from named list.
+	 * 
+	 * The names are ordered in as defined in the collection.
+	 * 
+	 * @param graphNames The from names to add.
+	 */
+	public void fromNamed(Collection<String> graphNames) {
+		for (String uri : graphNames) {
+			query.addNamedGraphURI(uri);
+		}
+	}
+
+	/**
+	 * Add the graph names to the from list.
+	 * @param graphName the name to add.
+	 */
+	public void from(String graphName) {
+		query.addGraphURI(graphName);
+	}
+
+	/**
+	 * Add the graph names to the named list. 
+	 * 
+	 * The names are ordered in as defined in the collection.
+	 * 
+	 * @param graphNames The names to add.
+	 */
+	public void from(Collection<String> graphNames) {
+		for (String uri : graphNames) {
+			query.addGraphURI(uri);
+		}
+	}
+
+	/**
+	 * Set the variables for field names that contain lists of strings.
+	 * 
+	 * Strings that start with "?" are assumed to be variable names and will be replaced
+	 * with matching node.toString() values. 
+	 * 
+	 * @param values The values to set.
+	 * @param fieldName The field name in Query that contain a list of strings.
+	 */
+	private void setVars(Map<Var, Node> values, String fieldName) {
+		if (values.isEmpty()) {
+			return;
+		}
+		try {
+			Field f = Query.class.getDeclaredField(fieldName);
+			f.setAccessible(true);
+			@SuppressWarnings("unchecked")
+			List<String> orig = (List<String>) f.get(query);
+			List<String> lst = null;
+			if (orig != null) {
+				lst = new ArrayList<String>();
+				for (String s : orig) {
+					Node n = null;
+					if (s.startsWith("?")) {
+						Var v = Var.alloc(s.substring(1));
+						n = values.get(v);
+					}
+					lst.add(n == null ? s : n.toString());
+				}
+				f.set(query, lst);
+			}
+		} catch (NoSuchFieldException e) {
+			throw new IllegalStateException(e.getMessage(), e);
+		} catch (SecurityException e) {
+			throw new IllegalStateException(e.getMessage(), e);
+		} catch (IllegalAccessException e) {
+			throw new IllegalStateException(e.getMessage(), e);
+		}
+	}
+
+	@Override
+	public void setVars(Map<Var, Node> values) {
+		setVars(values, "namedGraphURIs");
+		setVars(values, "graphURIs");
+	}
+
+	@Override
+	public void build() {
+		// nothing special to do
+	}
+
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/Handler.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/Handler.java
new file mode 100644
index 0000000..a6bf8d5
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/Handler.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.handlers;
+
+import java.util.Map;
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.sparql.core.Var;
+
+/**
+ * The base interface for handlers.
+ *
+ */
+public interface Handler {
+	/**
+	 * Set the values for variables managed by the handler implementation.
+	 * This method is called by the builder to set values handled by this Handler implementation.
+	 * @param values The map of variable to node value.
+	 */
+	public void setVars(Map<Var, Node> values);
+
+	/**
+	 * Called by the build process for this handler to perform any adjustments to the query before
+	 * the build completes.  The adjustments are made after setVars() has been called.
+	 */
+	public void build();
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/PrologHandler.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/PrologHandler.java
new file mode 100644
index 0000000..a821e4d
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/PrologHandler.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.handlers;
+
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.jena.riot.system.IRIResolver;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.query.Query;
+import com.hp.hpl.jena.shared.PrefixMapping;
+import com.hp.hpl.jena.sparql.core.Var;
+
+/**
+ * The proglog handler
+ *
+ */
+public class PrologHandler implements Handler {
+
+	// the query to modify.
+	private final Query query;
+
+	/**
+	 * Constructor.
+	 * @param query The query to handle.
+	 */
+	public PrologHandler(Query query) {
+		this.query = query;
+	}
+
+	/**
+	 * get the canonical prefix name.  
+	 * 
+	 * Removes ':' from the end of the name if present.
+	 * 
+	 * @param x The prefix name
+	 * @return The prefix name with the trialing ':' removed.
+	 */
+	private String canonicalPfx(String x) {
+		if (x.endsWith(":"))
+			return x.substring(0, x.length() - 1);
+		return x;
+	}
+
+	/**
+	 * Set the base for the query.  This is the IRI against which relative names will be resolved.
+	 * @param resolver The IRIResolver to set the base from.
+	 */
+	public void setBase(IRIResolver resolver) {
+		query.setBaseURI(resolver);
+
+	}
+
+	/**
+	 * Set the base for the query.  This is the IRI against which relative names will be resolved.
+	 * @param base The string to set the base from.
+	 */
+	public void setBase(String base) {
+		query.setBaseURI(base);
+	}
+
+	/**
+	 * Add a prefix to the prefix mapping.
+	 * @param pfx The prefix to add.
+	 * @param uri The uri to resolve the prefix to.
+	 */
+	public void addPrefix(String pfx, String uri) {
+		query.setPrefix(canonicalPfx(pfx), uri);
+	}
+
+	/**
+	 * Add the map of prefixes to the query prefixes.
+	 * @param prefixes The map of prefixs to URIs.
+	 */
+	public void addPrefixes(Map<String, String> prefixes) {
+		for (Map.Entry<String, String> e : prefixes.entrySet()) {
+			addPrefix(e.getKey(), e.getValue());
+		}
+	}
+
+	/**
+	 * Add prefixes from a prefix mapping.
+	 * @param prefixes THe prefix mapping to add from.
+	 */
+	public void addPrefixes(PrefixMapping prefixes) {
+		query.getPrefixMapping().setNsPrefixes(prefixes);
+	}
+
+	/**
+	 * Add the settings from the prolog handler argument.
+	 * @param pfxHandler The PrologHandler to read from
+	 */
+	public void addAll(PrologHandler pfxHandler) {
+		String val = StringUtils.defaultIfEmpty(pfxHandler.query.getBaseURI(),
+				query.getBaseURI());
+		if (val != null) {
+			setBase(val);
+		}
+		addPrefixes(pfxHandler.query.getPrefixMapping());
+	}
+
+	@Override
+	public void setVars(Map<Var, Node> values) {
+		// nothing to do
+	}
+
+	@Override
+	public void build() {
+		// no special operation to perform
+	}
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/SelectHandler.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/SelectHandler.java
new file mode 100644
index 0000000..70e94a7
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/SelectHandler.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.handlers;
+
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.query.Query;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.core.VarExprList;
+
+/**
+ * A Select clause handler.
+ *
+ */
+public class SelectHandler implements Handler {
+
+	// the query to handle
+	private final Query query;
+
+	/**
+	 * Constructor.
+	 * @param query The query to manage.
+	 */
+	public SelectHandler(Query query) {
+		this.query = query;
+		setDistinct(query.isDistinct());
+		setReduced(query.isReduced());
+	}
+
+	/**
+	 * Set the distinct flag.
+	 * Set or unset the distinct flag.
+	 * Will set the reduced flag if it was previously set.
+	 * @param state the state to set the distinct flag to.
+	 */
+	public void setDistinct(boolean state) {
+		query.setDistinct(state);
+		if (state) {
+			query.setReduced(false);
+		}
+	}
+
+	/**
+	 * Set the reduced flag.
+	 * Set or unset the reduced flag.
+	 * Will set the reduced flag if it was previously set.
+	 * @param state the state to set the reduced flag to.
+	 */
+	public void setReduced(boolean state) {
+		query.setReduced(state);
+		if (state) {
+			query.setDistinct(false);
+		}
+	}
+
+	/**
+	 * Add a variable to the select.
+	 * If the variable is the variables are set to star.
+	 * @param var The variable to add.
+	 */
+	public void addVar(Var var) {
+		if (var == null) {
+			query.setQueryResultStar(true);
+		} else {
+			query.setQueryResultStar(false);
+			query.addResultVar(var);
+		}
+	}
+
+	/**
+	 * Get the list of variables from the query.
+	 * @return The list of variables in the query.
+	 */
+	public List<Var> getVars() {
+		return query.getProjectVars();
+	}
+
+	/**
+	 * Add all the variables from the select handler variable.
+	 * @param selectHandler The select handler to copy the variables from.
+	 */
+	public void addAll(SelectHandler selectHandler) {
+
+		setReduced(selectHandler.query.isReduced());
+		setDistinct(selectHandler.query.isDistinct());
+		query.setQueryResultStar(selectHandler.query.isQueryResultStar());
+
+		try {
+			Field f = Query.class.getDeclaredField("projectVars");
+			f.setAccessible(true);
+			VarExprList projectVars = (VarExprList) f.get(selectHandler.query);
+			f.set(query, new VarExprList(projectVars));
+		} catch (NoSuchFieldException e) {
+			throw new IllegalStateException(e);
+		} catch (SecurityException e) {
+			throw new IllegalStateException(e);
+		} catch (IllegalAccessException e) {
+			throw new IllegalStateException(e);
+		}
+	}
+
+	@Override
+	public void setVars(Map<Var, Node> values) {
+		// nothing to do
+	}
+
+	@Override
+	public void build() {
+		if (query.getProject().getVars().isEmpty()) {
+			query.setQueryResultStar(true);
+		}
+		// handle the SELECT * case
+		query.getProjectVars();
+	}
+}
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/SolutionModifierHandler.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/SolutionModifierHandler.java
new file mode 100644
index 0000000..50838f5
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/SolutionModifierHandler.java
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.handlers;
+
+import java.io.ByteArrayInputStream;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.jena.arq.querybuilder.rewriters.ExprRewriter;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.query.Query;
+import com.hp.hpl.jena.query.SortCondition;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.core.VarExprList;
+import com.hp.hpl.jena.sparql.expr.Expr;
+import com.hp.hpl.jena.sparql.expr.ExprList;
+import com.hp.hpl.jena.sparql.expr.ExprVar;
+import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
+import com.hp.hpl.jena.sparql.lang.sparql_11.SPARQLParser11;
+
+/**
+ * The Solution Modifier handerl.
+ *
+ */
+public class SolutionModifierHandler implements Handler {
+	/**
+	 * The order for the ORDER BY modifiers.
+	 */
+	public e

<TRUNCATED>