http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/SelectHandler.java
----------------------------------------------------------------------
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();
+       }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/SolutionModifierHandler.java
----------------------------------------------------------------------
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 enum Order {
+               ASCENDING, DESCENDING
+       };
+
+       // the query to modify
+       private final Query query;
+
+       /**
+        * Constructor
+        * @param query The query to modify.
+        */
+       public SolutionModifierHandler(Query query) {
+               this.query = query;
+       }
+
+       /**
+        * Copy all the modifications from the Solution Modifier argument
+        * @param solutionModifier The solution modifier to copy from.
+        */
+       public void addAll(SolutionModifierHandler solutionModifier) {
+               List<SortCondition> lst = solutionModifier.query.getOrderBy();
+               if (lst != null) {
+                       for (SortCondition sc : lst) {
+                               query.addOrderBy(sc);
+                       }
+               }
+               query.getGroupBy().addAll(solutionModifier.query.getGroupBy());
+               
query.getHavingExprs().addAll(solutionModifier.query.getHavingExprs());
+               query.setLimit(solutionModifier.query.getLimit());
+               query.setOffset(solutionModifier.query.getOffset());
+       }
+
+       /**
+        * Add an order by variable.
+        * @param varName The variable name.
+        */
+       public void addOrderBy(String varName) {
+               query.addOrderBy(varName, Query.ORDER_DEFAULT);
+       }
+
+       /**
+        * Add an order by variable.
+        * @param varName The variable name.
+        * @param order The direction for the ordering.
+        */
+       public void addOrderBy(String varName, Order order) {
+               query.addOrderBy(varName,
+                               order == Order.ASCENDING ? Query.ORDER_ASCENDING
+                                               : Query.ORDER_DESCENDING);
+       }
+
+       /**
+        * Add an order by clause
+        * @param condition The SortCondition to add to the order by.
+        */
+       public void addOrderBy(SortCondition condition) {
+               query.addOrderBy(condition);
+       }
+
+       /**
+        * Add an expression to the order by clause.
+        * @param expr The expression to add.
+        */
+       public void addOrderBy(Expr expr) {
+               query.addOrderBy(expr, Query.ORDER_DEFAULT);
+       }
+
+       public void addOrderBy(Expr expr, Order order) {
+               query.addOrderBy(expr, order == Order.ASCENDING ? 
Query.ORDER_ASCENDING
+                               : Query.ORDER_DESCENDING);
+       }
+
+       /**
+        * Add a node to the order by clause.
+        * @param node
+        */
+       public void addOrderBy(Node node) {
+               query.addOrderBy(node, Query.ORDER_DEFAULT);
+       }
+
+       /**
+        * Add a node to add to the order by clause.
+        * @param node The node to add
+        * @param order The direction of the ordering. 
+        */
+       public void addOrderBy(Node node, Order order) {
+               query.addOrderBy(node, order == Order.ASCENDING ? 
Query.ORDER_ASCENDING
+                               : Query.ORDER_DESCENDING);
+       }
+
+       /**
+        * Add a variable to the group by clause. 
+        * @param varName The variable name to add.
+        */
+       public void addGroupBy(String varName) {
+               query.addGroupBy(varName);
+       }
+
+       /**
+        * Add an expression to the group by clause. 
+        * @param expr The expression to add.
+        */
+       public void addGroupBy(Expr expr) {
+               query.addGroupBy(expr);
+       }
+
+       /**
+        * Add a node to the group by clause. 
+        * @param node The node to add.
+        */
+       public void addGroupBy(Node node) {
+               query.addGroupBy(node);
+       }
+
+       /**
+        * Add var and expression to the group by clause.
+        * @param var The variable to add.
+        * @param expr The expression to add.
+        */
+       public void addGroupBy(Var var, Expr expr) {
+               query.addGroupBy(var, expr);
+       }
+
+       /**
+        * Add a having expression.
+        * @param expression The expression to add
+        * @throws ParseException If the expression can not be parsed.
+        */
+       public void addHaving(String expression) throws ParseException {
+               String havingClause = "HAVING (" + expression + " )";
+               SPARQLParser11 parser = new SPARQLParser11(new 
ByteArrayInputStream(
+                               havingClause.getBytes()));
+               parser.setQuery(query);
+               parser.HavingClause();
+       }
+
+       /**
+        * Add a node to the having clause.
+        * @param exprNode The node to add.
+        */
+       public void addHaving(Node exprNode) {
+               query.addHavingCondition(new ExprVar(exprNode));
+       }
+
+       /**
+        * Add a variable to the having clause.
+        * @param var The variable to add.
+        */
+       public void addHaving(Var var) {
+               query.addHavingCondition(new ExprVar(var));
+       }
+
+       /**
+        * Add an expression to the having clause.
+        * @param expr The expression to add.
+        */
+       public void addHaving(Expr expr) {
+               query.addHavingCondition(expr);
+       }
+
+       /**
+        * Set the limit for the number of results to return.
+        * Setting the limit to zero (0) or removes the limit.
+        * @param limit THe limit to set.
+        */
+       public void setLimit(int limit) {
+               query.setLimit(limit < 1 ? Query.NOLIMIT : limit);
+       }
+
+       /**
+        * Set the offset for the results to return.
+        * Setting the offset to zero (0) or removes the offset.
+        * @param offset THe offset to set.
+        */
+       public void setOffset(int offset) {
+               query.setOffset(offset < 1 ? Query.NOLIMIT : offset);
+       }
+
+       @Override
+       public void setVars(Map<Var, Node> values) {
+               if (values.isEmpty()) {
+                       return;
+               }
+
+               ExprRewriter exprRewriter = new ExprRewriter(values);
+
+               ExprList having = exprRewriter.rewrite(new ExprList(query
+                               .getHavingExprs()));
+               List<SortCondition> orderBy = exprRewriter
+                               .rewriteSortConditionList(query.getOrderBy());
+
+               VarExprList groupBy = exprRewriter.rewrite(query.getGroupBy());
+
+               query.getHavingExprs().clear();
+               query.getHavingExprs().addAll(having.getList());
+               if (orderBy != null) {
+                       if (query.getOrderBy() == null) {
+                               for (SortCondition sc : orderBy) {
+                                       query.addOrderBy(sc);
+                               }
+                       } else {
+                               query.getOrderBy().clear();
+                               query.getOrderBy().addAll(orderBy);
+                       }
+               }
+
+               try {
+                       Field f = Query.class.getDeclaredField("groupVars");
+                       f.setAccessible(true);
+                       f.set(query, groupBy);
+               } catch (NoSuchFieldException e) {
+                       throw new IllegalStateException(e);
+               } catch (SecurityException e) {
+                       throw new IllegalStateException(e);
+               } catch (IllegalAccessException e) {
+                       throw new IllegalStateException(e);
+               }
+
+       }
+
+       @Override
+       public void build() {
+               // no special commands.
+       }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java
 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java
new file mode 100644
index 0000000..5a61cc8
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java
@@ -0,0 +1,310 @@
+/*
+ * 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.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.jena.arq.querybuilder.SelectBuilder;
+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.rewriters.ElementRewriter;
+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.Var;
+import com.hp.hpl.jena.sparql.expr.Expr;
+import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
+import com.hp.hpl.jena.sparql.lang.sparql_11.SPARQLParser11;
+import com.hp.hpl.jena.sparql.syntax.Element;
+import com.hp.hpl.jena.sparql.syntax.ElementFilter;
+import com.hp.hpl.jena.sparql.syntax.ElementGroup;
+import com.hp.hpl.jena.sparql.syntax.ElementNamedGraph;
+import com.hp.hpl.jena.sparql.syntax.ElementOptional;
+import com.hp.hpl.jena.sparql.syntax.ElementSubQuery;
+import com.hp.hpl.jena.sparql.syntax.ElementTriplesBlock;
+import com.hp.hpl.jena.sparql.syntax.ElementUnion;
+
+/**
+ * The where handler
+ *
+ */
+public class WhereHandler implements Handler {
+
+       // the query to modify
+       private final Query query;
+
+       /**
+        * Constructor.
+        * @param query The query to manipulate.
+        */
+       public WhereHandler(Query query) {
+               this.query = query;
+       }
+
+       /**
+        * Add all where attributes from the Where Handler argument.
+        * @param whereHandler The Where Handler to copy from.
+        */
+       public void addAll(WhereHandler whereHandler) {
+               Element e = whereHandler.query.getQueryPattern();
+               Element locE = query.getQueryPattern();
+               if (e != null) {
+                       if (locE == null) {
+                               query.setQueryPattern(e);
+                       } else {
+                               ElementTriplesBlock locEtb = 
(ElementTriplesBlock) locE;
+                               ElementTriplesBlock etp = (ElementTriplesBlock) 
e;
+                               Iterator<Triple> iter = etp.patternElts();
+                               while (iter.hasNext()) {
+                                       locEtb.addTriple(iter.next());
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Get the base element from the where clause.
+        * If the clause does not contain an element return the element group, 
otherwise return the 
+        * enclosed elelment.
+        * @return the base element.
+        */
+       private Element getElement() {
+               ElementGroup eg = getClause();
+               if (eg.getElements().size() == 1) {
+                       return eg.getElements().get(0);
+               }
+               return eg;
+       }
+
+       /**
+        * Get the element group for the clause.
+        * if HTe element group is not set, create and set it.
+        * @return The element group.
+        */
+       private ElementGroup getClause() {
+               ElementGroup e = (ElementGroup) query.getQueryPattern();
+               if (e == null) {
+                       e = new ElementGroup();
+                       query.setQueryPattern(e);
+               }
+               return e;
+       }
+
+       /**
+        * Test that a triple is valid.
+        * Throws an IllegalArgumentException if the triple is not valid.
+        * @param t The trip to test.
+        */
+       private void testTriple(Triple t) {
+               // verify Triple is valid
+               boolean validSubject = t.getSubject().isURI()
+                               || t.getSubject().isBlank() || 
t.getSubject().isVariable()
+                               || t.getSubject().equals(Node.ANY);
+               boolean validPredicate = t.getPredicate().isURI()
+                               || t.getPredicate().isVariable()
+                               || t.getPredicate().equals(Node.ANY);
+               boolean validObject = t.getObject().isURI()
+                               || t.getObject().isLiteral() || 
t.getObject().isBlank()
+                               || t.getObject().isVariable() || 
t.getObject().equals(Node.ANY);
+
+               if (!validSubject || !validPredicate || !validObject) {
+                       StringBuilder sb = new StringBuilder();
+                       if (!validSubject) {
+                               sb.append(String
+                                               .format("Subject (%s) must be a 
URI, blank, variable, or a wildcard. %n",
+                                                               
t.getSubject()));
+                       }
+                       if (!validPredicate) {
+                               sb.append(String
+                                               .format("Predicate (%s) must be 
a URI , variable, or a wildcard. %n",
+                                                               
t.getPredicate()));
+                       }
+                       if (!validObject) {
+                               sb.append(String
+                                               .format("Object (%s) must be a 
URI, literal, blank, , variable, or a wildcard. %n",
+                                                               t.getObject()));
+                       }
+                       if (!validSubject || !validPredicate) {
+                               sb.append(String
+                                               .format("Is a prefix missing?  
Prefix must be defined before use. %n"));
+                       }
+                       throw new IllegalArgumentException(sb.toString());
+               }
+       }
+
+       /**
+        * Add the triple to the where clause
+        * @param t The triple to add.
+        * @throws IllegalArgumentException If the triple is not a valid triple 
for a where clause.
+        */
+       public void addWhere(Triple t) throws IllegalArgumentException {
+               testTriple(t);
+               ElementGroup eg = getClause();
+               List<Element> lst = eg.getElements();
+               if (lst.isEmpty()) {
+                       ElementTriplesBlock etb = new ElementTriplesBlock();
+                       etb.addTriple(t);
+                       eg.addElement(etb);
+               } else {
+                       Element e = lst.get(lst.size() - 1);
+                       if (e instanceof ElementTriplesBlock) {
+                               ElementTriplesBlock etb = (ElementTriplesBlock) 
e;
+                               etb.addTriple(t);
+                       } else {
+                               ElementTriplesBlock etb = new 
ElementTriplesBlock();
+                               etb.addTriple(t);
+                               eg.addElement(etb);
+                       }
+
+               }
+       }
+
+       /**
+        * Add an optional triple to the where clause
+        * @param t The triple to add.
+        * @throws IllegalArgumentException If the triple is not a valid triple 
for a where clause.
+        */
+       public void addOptional(Triple t) throws IllegalArgumentException {
+               testTriple(t);
+               ElementTriplesBlock etb = new ElementTriplesBlock();
+               etb.addTriple(t);
+               ElementOptional opt = new ElementOptional(etb);
+               getClause().addElement(opt);
+       }
+
+       /**
+        * Add an expression string as a filter.
+        * @param expression The expression string to add.
+        * @throws ParseException If the expression can not be parsed.
+        */
+       public void addFilter(String expression) throws ParseException {
+               String filterClause = "FILTER( " + expression + ")";
+               SPARQLParser11 parser = new SPARQLParser11(new 
ByteArrayInputStream(
+                               filterClause.getBytes()));
+               getClause().addElement(parser.Filter());
+       }
+
+       /**
+        * add an expression as a filter.
+        * @param expr The expression to add.
+        */
+       public void addFilter(Expr expr) {
+               getClause().addElement(new ElementFilter(expr));
+       }
+
+       /**
+        * Add a subquery to the where clause.
+        * @param subQuery The sub query to add.
+        */
+       public void addSubQuery(SelectBuilder subQuery) {
+               getClause().addElement(makeSubQuery(subQuery));
+       }
+
+       /**
+        * Convert a subquery into a subquery element.
+        * @param subQuery The sub query to convert
+        * @return THe converted element.
+        */
+       private ElementSubQuery makeSubQuery(SelectBuilder subQuery) {
+               Query q = new Query();
+               PrologHandler ph = new PrologHandler(query);
+               ph.addAll(subQuery.getPrologHandler());
+
+               for (Var v : subQuery.getVars()) {
+                       q.addResultVar(v);
+                       q.setQuerySelectType();
+               }
+
+               if (subQuery instanceof ConstructClause) {
+                       ConstructHandler ch = new ConstructHandler(q);
+                       ch.addAll(((ConstructClause<?>) 
subQuery).getConstructHandler());
+
+               }
+               if (subQuery instanceof DatasetClause) {
+                       DatasetHandler dh = new DatasetHandler(q);
+                       dh.addAll(((DatasetClause<?>) 
subQuery).getDatasetHandler());
+
+               }
+               if (subQuery instanceof SolutionModifierClause) {
+                       SolutionModifierHandler smh = new 
SolutionModifierHandler(q);
+                       smh.addAll(((SolutionModifierClause<?>) subQuery)
+                                       .getSolutionModifierHandler());
+
+               }
+               if (subQuery instanceof WhereClause) {
+                       WhereHandler wh = new WhereHandler(q);
+                       wh.addAll(((WhereClause<?>) 
subQuery).getWhereHandler());
+
+               }
+               return new ElementSubQuery(q);
+
+       }
+
+       /**
+        * Add a union to the where clause.
+        * @param subQuery The subquery to add as the union.
+        */
+       public void addUnion(SelectBuilder subQuery) {
+               ElementUnion union = new ElementUnion();
+               if (subQuery.getVars().size() > 0) {
+                       union.addElement(makeSubQuery(subQuery));
+               } else {
+                       PrologHandler ph = new PrologHandler(query);
+                       ph.addAll(subQuery.getPrologHandler());
+                       for (Element el : subQuery.getWhereHandler().getClause()
+                                       .getElements()) {
+                               union.addElement(el);
+                       }
+               }
+               getClause().addElement(union);
+       }
+
+       /**
+        * Add a graph to the where clause.
+        * @param graph The name of the graph.
+        * @param subQuery The where handler that defines the graph.
+        */
+       public void addGraph(Node graph, WhereHandler subQuery) {
+               getClause().addElement(
+                               new ElementNamedGraph(graph, 
subQuery.getElement()));
+       }
+
+       @Override
+       public void setVars(Map<Var, Node> values) {
+               if (values.isEmpty()) {
+                       return;
+               }
+
+               Element e = query.getQueryPattern();
+               if (e != null) {
+                       ElementRewriter r = new ElementRewriter(values);
+                       e.visit(r);
+                       query.setQueryPattern(r.getResult());
+               }
+       }
+
+       @Override
+       public void build() {
+               // no special operations required.
+       }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/package-info.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/package-info.java
 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/package-info.java
new file mode 100644
index 0000000..e312b61
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/package-info.java
@@ -0,0 +1,9 @@
+/**
+ * Classes that implement SPARQL clauses but do not return instances of the 
builder.
+ * 
+ * These classes are used by the various Builder implementations to 
consistently implement
+ * the various clauses.
+ * 
+ * In most cases users of the Query Builder module will not need to manipulate 
these directly.
+ */
+package org.apache.jena.arq.querybuilder.handlers;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/package-info.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/package-info.java
 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/package-info.java
new file mode 100644
index 0000000..7fb6ca4
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/package-info.java
@@ -0,0 +1,9 @@
+/**
+ * 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.
+ * <p>
+ * The package version should align with the apache-jena-libs version.
+ * </p>
+ */
+package org.apache.jena.arq.querybuilder;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/AbstractRewriter.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/AbstractRewriter.java
 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/AbstractRewriter.java
new file mode 100644
index 0000000..79cbfe4
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/AbstractRewriter.java
@@ -0,0 +1,222 @@
+/*
+ * 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.rewriters;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.sparql.core.TriplePath;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.core.VarExprList;
+import com.hp.hpl.jena.sparql.engine.binding.Binding;
+import com.hp.hpl.jena.sparql.engine.binding.BindingHashMap;
+import com.hp.hpl.jena.sparql.expr.Expr;
+import com.hp.hpl.jena.sparql.util.ExprUtils;
+
+/**
+ * The base class for rewriters.
+ * 
+ * Rewriters push and pop items on the stack during processing.
+ *
+ * @param <T> The type of object being rewritten.
+ */
+public class AbstractRewriter<T> {
+       // The map of variables to nodes.
+       protected final Map<Var, Node> values;
+       // A stack used in processing.
+       private final Stack<T> result = new Stack<T>();
+
+       /**
+        * Constructor
+        * @param values The values to map.
+        */
+       protected AbstractRewriter(Map<Var, Node> values) {
+               this.values = values;
+       }
+
+       /**
+        * Push the value on the stack.
+        * @param value The value to push.
+        */
+       protected final void push(T value) {
+               result.push(value);
+       }
+
+       /**
+        * pop the value from the stack.
+        * @return The value from the top of the stack.
+        */
+       protected final T pop() {
+               return result.pop();
+       }
+
+       /**
+        * Return true if the stack is empty.
+        * @return true if the stack is empty, false otherwise.
+        */
+       protected final boolean isEmpty() {
+               return result.isEmpty();
+       }
+
+       /**
+        * Get the result from the rewriter.
+        * Returns the top of the stack.
+        * @return The final result or null if there is no answer.
+        */
+       public final T getResult() {
+               if (isEmpty()) {
+                       return null;
+               }
+               return pop();
+       }
+
+       /**
+        * Rewrite a triple path.
+        * @param t The triple path to rewrite.
+        * @return the triple path after rewriting.
+        */
+       protected final TriplePath rewrite(TriplePath t) {
+               if (t.getPath() == null) {
+                       return new TriplePath(new 
Triple(changeNode(t.getSubject()),
+                                       changeNode(t.getPredicate()), 
changeNode(t.getObject())));
+               } else {
+                       PathRewriter transform = new PathRewriter(values);
+                       t.getPath().visit(transform);
+                       return new TriplePath(changeNode(t.getSubject()),
+                                       transform.getResult(), 
changeNode(t.getObject()));
+               }
+       }
+
+       /**
+        * Rewrite a triple.
+        * @param t The triple to rewrite.
+        * @return The rewritten triple.
+        */
+       protected final Triple rewrite(Triple t) {
+               return new Triple(changeNode(t.getSubject()),
+                               changeNode(t.getPredicate()), 
changeNode(t.getObject()));
+       }
+
+       /**
+        * If the node is a variable perform any necessary rewrite, otherwise 
return the node.
+        * @param n The node to to rewrite.
+        * @return the rewriten node.
+        */
+       protected final Node changeNode(Node n) {
+               if (n.isVariable()) {
+                       Var v = Var.alloc(n);
+
+                       if (values.containsKey(v)) {
+                               return values.get(v);
+                       }
+               }
+               return n;
+       }
+
+       /**
+        * Change all the nodes in the list.
+        * If a node is a variable perform any necessary rewrite, otherwise 
return the node.
+        * @param src a list of nodes to change.
+        * @return The list of nodes.
+        */
+       protected final List<Node> changeNodes(List<Node> src) {
+               List<Node> lst = new ArrayList<Node>();
+               for (Node t : src) {
+                       lst.add(changeNode(t));
+               }
+               return lst;
+       }
+
+       /**
+        * Rewrite a list of triples.
+        * @param src The list of triples to rewrite.
+        * @return The list of rewritten triples.
+        */
+       public final List<Triple> rewrite(List<Triple> src) {
+               List<Triple> lst = new ArrayList<Triple>();
+               for (Triple t : src) {
+                       lst.add(rewrite(t));
+               }
+               return lst;
+       }
+
+       /**
+        * Rewrite a binding.
+        * @param binding The binding to rewrite
+        * @return The rewritten binding.
+        */
+       protected final Binding rewrite(Binding binding) {
+               BindingHashMap retval = new BindingHashMap();
+               Iterator<Var> iter = binding.vars();
+               while (iter.hasNext()) {
+                       Var v = iter.next();
+                       Node n = changeNode(binding.get(v));
+                       n = n.equals(v) ? binding.get(v) : n;
+                       retval.add(v, n);
+               }
+               return retval;
+       }
+
+       /**
+        * Rewrite a variable expression list.
+        * @param lst The variable expression list.
+        * @return the rewritten variable expresson list.
+        */
+       public final VarExprList rewrite(VarExprList lst) {
+
+               VarExprList retval = new VarExprList();
+               for (Var v : lst.getVars()) {
+                       Node n = values.get(v);
+                       if (n != null) {
+                               if (n.isVariable()) {
+                                       retval.add(Var.alloc(n));
+                               }
+                       } else {
+                               retval.add(v);
+                       }
+               }
+
+               for (Map.Entry<Var, Expr> entry : lst.getExprs().entrySet()) {
+                       Expr target = ExprUtils.nodeToExpr(entry.getKey());
+                       Node n = values.get(entry.getKey());
+                       Var v = entry.getKey();
+                       Expr e = entry.getValue();
+                       if (n != null) {
+                               if (n.isVariable()) {
+                                       v = Var.alloc(n);
+                                       if (target.equals(e)) {
+                                               e = ExprUtils.nodeToExpr(n);
+                                       }
+                               } else {
+                                       v = null;
+                               }
+                       }
+                       if (v != null) {
+                               retval.add(v, e);
+                       }
+               }
+               return retval;
+
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/ElementRewriter.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/ElementRewriter.java
 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/ElementRewriter.java
new file mode 100644
index 0000000..a0a6427
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/ElementRewriter.java
@@ -0,0 +1,213 @@
+/*
+ * 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.rewriters;
+
+import java.util.Iterator;
+import java.util.Map;
+import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.graph.Triple;
+import com.hp.hpl.jena.sparql.core.TriplePath;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.engine.binding.Binding;
+import com.hp.hpl.jena.sparql.syntax.Element;
+import com.hp.hpl.jena.sparql.syntax.ElementAssign;
+import com.hp.hpl.jena.sparql.syntax.ElementBind;
+import com.hp.hpl.jena.sparql.syntax.ElementData;
+import com.hp.hpl.jena.sparql.syntax.ElementDataset;
+import com.hp.hpl.jena.sparql.syntax.ElementExists;
+import com.hp.hpl.jena.sparql.syntax.ElementFilter;
+import com.hp.hpl.jena.sparql.syntax.ElementGroup;
+import com.hp.hpl.jena.sparql.syntax.ElementMinus;
+import com.hp.hpl.jena.sparql.syntax.ElementNamedGraph;
+import com.hp.hpl.jena.sparql.syntax.ElementNotExists;
+import com.hp.hpl.jena.sparql.syntax.ElementOptional;
+import com.hp.hpl.jena.sparql.syntax.ElementPathBlock;
+import com.hp.hpl.jena.sparql.syntax.ElementService;
+import com.hp.hpl.jena.sparql.syntax.ElementSubQuery;
+import com.hp.hpl.jena.sparql.syntax.ElementTriplesBlock;
+import com.hp.hpl.jena.sparql.syntax.ElementUnion;
+import com.hp.hpl.jena.sparql.syntax.ElementVisitor;
+
+/**
+ * A rewriter that implements an ElementVisitor
+ *
+ */
+public class ElementRewriter extends AbstractRewriter<Element> implements
+               ElementVisitor {
+
+       /**
+        * Constructor
+        * @param values The values to rewrite with.
+        */
+       public ElementRewriter(Map<Var, Node> values) {
+               super(values);
+       }
+
+       @Override
+       public void visit(ElementTriplesBlock el) {
+               ElementTriplesBlock newBlock = new ElementTriplesBlock();
+               Iterator<Triple> tIter = el.patternElts();
+               while (tIter.hasNext()) {
+                       newBlock.addTriple(rewrite(tIter.next()));
+               }
+               push(newBlock);
+       }
+
+       @Override
+       public void visit(ElementPathBlock el) {
+               ElementPathBlock newBlock = new ElementPathBlock();
+               Iterator<TriplePath> tIter = el.patternElts();
+               while (tIter.hasNext()) {
+                       newBlock.addTriplePath(rewrite(tIter.next()));
+               }
+               push(newBlock);
+       }
+
+       @Override
+       public void visit(ElementFilter el) {
+               ExprRewriter exprRewriter = new ExprRewriter(values);
+               el.getExpr().visit(exprRewriter);
+               push(new ElementFilter(exprRewriter.getResult()));
+       }
+
+       @Override
+       public void visit(ElementAssign el) {
+               Node n = changeNode(el.getVar());
+               if (n.equals(el.getVar())) {
+                       ExprRewriter exprRewriter = new ExprRewriter(values);
+                       el.getExpr().visit(exprRewriter);
+                       push(new ElementAssign(el.getVar(), 
exprRewriter.getResult()));
+               } else {
+                       // push( new ElementAssign( el.getVar(), 
NodeValue.makeNode( n )) );
+                       // no op
+                       push(new ElementTriplesBlock());
+               }
+
+       }
+
+       @Override
+       public void visit(ElementBind el) {
+               Node n = changeNode(el.getVar());
+               if (n.equals(el.getVar())) {
+                       ExprRewriter exprRewriter = new ExprRewriter(values);
+                       el.getExpr().visit(exprRewriter);
+                       push(new ElementBind(el.getVar(), 
exprRewriter.getResult()));
+               } else {
+                       // push( new ElementBind( el.getVar(), 
NodeValue.makeNode( n )) );
+                       // no op
+                       push(new ElementTriplesBlock());
+               }
+       }
+
+       @Override
+       public void visit(ElementData el) {
+               ElementData retval = new ElementData();
+               Iterator<Var> vars = el.getVars().iterator();
+               Iterator<Binding> bindings = el.getRows().iterator();
+               while (vars.hasNext()) {
+                       Var v = vars.next();
+                       if (values.containsKey(v)) {
+                               bindings.next(); // skip the binding
+                       } else {
+                               retval.add(v);
+                               retval.add(rewrite(bindings.next()));
+                       }
+               }
+               push(retval);
+
+       }
+
+       @Override
+       public void visit(ElementUnion el) {
+               ElementUnion retval = new ElementUnion();
+               for (Element e : el.getElements()) {
+                       e.visit(this);
+                       retval.addElement(getResult());
+               }
+               push(retval);
+       }
+
+       @Override
+       public void visit(ElementOptional el) {
+               el.getOptionalElement().visit(this);
+               push(new ElementOptional(getResult()));
+       }
+
+       @Override
+       public void visit(ElementGroup el) {
+               ElementGroup retval = new ElementGroup();
+               for (Element e : el.getElements()) {
+                       e.visit(this);
+                       retval.addElement(getResult());
+               }
+               push(retval);
+       }
+
+       @Override
+       public void visit(ElementDataset el) {
+               Element pattern = null;
+               if (el.getPatternElement() != null) {
+                       el.getPatternElement().visit(this);
+                       pattern = getResult();
+               }
+               push(new ElementDataset(el.getDataset(), pattern));
+       }
+
+       @Override
+       public void visit(ElementNamedGraph el) {
+               Node n = el.getGraphNameNode();
+               if (n != null) {
+                       n = changeNode(n);
+               }
+               el.getElement().visit(this);
+               push(new ElementNamedGraph(n, getResult()));
+       }
+
+       @Override
+       public void visit(ElementExists el) {
+               el.getElement().visit(this);
+               push(new ElementExists(getResult()));
+       }
+
+       @Override
+       public void visit(ElementNotExists el) {
+               el.getElement().visit(this);
+               push(new ElementNotExists(getResult()));
+       }
+
+       @Override
+       public void visit(ElementMinus el) {
+               el.getMinusElement().visit(this);
+               push(new ElementMinus(getResult()));
+       }
+
+       @Override
+       public void visit(ElementService el) {
+               el.getElement().visit(this);
+               push(new ElementService(changeNode(el.getServiceNode()), 
getResult(),
+                               el.getSilent()));
+       }
+
+       @Override
+       public void visit(ElementSubQuery el) {
+               push(new ElementSubQuery(AbstractQueryBuilder.rewrite(
+                               AbstractQueryBuilder.clone(el.getQuery()), 
values)));
+       }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/ExprRewriter.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/ExprRewriter.java
 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/ExprRewriter.java
new file mode 100644
index 0000000..79179ff
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/ExprRewriter.java
@@ -0,0 +1,203 @@
+/*
+ * 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.rewriters;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.query.SortCondition;
+import com.hp.hpl.jena.sparql.algebra.Op;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.expr.Expr;
+import com.hp.hpl.jena.sparql.expr.ExprAggregator;
+import com.hp.hpl.jena.sparql.expr.ExprFunction0;
+import com.hp.hpl.jena.sparql.expr.ExprFunction1;
+import com.hp.hpl.jena.sparql.expr.ExprFunction2;
+import com.hp.hpl.jena.sparql.expr.ExprFunction3;
+import com.hp.hpl.jena.sparql.expr.ExprFunctionN;
+import com.hp.hpl.jena.sparql.expr.ExprFunctionOp;
+import com.hp.hpl.jena.sparql.expr.ExprList;
+import com.hp.hpl.jena.sparql.expr.ExprNode;
+import com.hp.hpl.jena.sparql.expr.ExprVar;
+import com.hp.hpl.jena.sparql.expr.ExprVisitor;
+import com.hp.hpl.jena.sparql.expr.NodeValue;
+import com.hp.hpl.jena.sparql.syntax.Element;
+
+/**
+ * A rewriter that implements an ExprVisitor
+ *
+ */
+public class ExprRewriter extends AbstractRewriter<Expr> implements 
ExprVisitor {
+
+       /**
+        * Constructor.
+        * @param values the values to replace.
+        */
+       public ExprRewriter(Map<Var, Node> values) {
+               super(values);
+       }
+
+       @Override
+       public void startVisit() {
+               // TODO Auto-generated method stub
+
+       }
+
+       @Override
+       public void visit(ExprFunction0 func) {
+               push(func);
+       }
+
+       @Override
+       public void visit(ExprFunction1 func) {
+               func.getArg().visit(this);
+               push(func.copy(pop()));
+
+       }
+
+       @Override
+       public void visit(ExprFunction2 func) {
+               // reverse order so they pop in the right order
+               func.getArg2().visit(this);
+               func.getArg1().visit(this);
+               push(func.copy(pop(), pop()));
+       }
+
+       @Override
+       public void visit(ExprFunction3 func) {
+               func.getArg3().visit(this);
+               func.getArg2().visit(this);
+               func.getArg1().visit(this);
+               push(func.copy(pop(), pop(), pop()));
+       }
+
+       @Override
+       public void visit(ExprFunctionN func) {
+               ExprList exprList = rewrite(new ExprList(func.getArgs()));
+               ExprFunctionN retval = (ExprFunctionN) func.deepCopy();
+               setExprList(retval, exprList);
+               push(retval);
+       }
+
+       private void setExprList(ExprNode n, ExprList exprList) {
+               try {
+                       Field f = n.getClass().getField("ExprList");
+                       f.setAccessible(true);
+                       f.set(n, exprList);
+               } catch (NoSuchFieldException e) {
+                       throw new IllegalStateException(e);
+               } catch (SecurityException e) {
+                       throw new IllegalStateException(e);
+               } catch (IllegalAccessException e) {
+                       throw new IllegalStateException(e);
+               }
+       }
+
+       @Override
+       public void visit(ExprFunctionOp funcOp) {
+               ElementRewriter elementRewriter = new ElementRewriter(values);
+               funcOp.getElement().visit(elementRewriter);
+               OpRewriter opRewriter = new OpRewriter(values);
+               funcOp.getGraphPattern().visit(opRewriter);
+
+               try {
+                       Constructor<? extends ExprFunctionOp> con = 
funcOp.getClass()
+                                       .getConstructor(Element.class, 
Op.class);
+                       push(con.newInstance(elementRewriter.pop(), 
opRewriter.pop()));
+               } catch (NoSuchMethodException e) {
+                       throw new IllegalStateException(e);
+               } catch (SecurityException e) {
+                       throw new IllegalStateException(e);
+               } catch (InstantiationException e) {
+                       throw new IllegalStateException(e);
+               } catch (IllegalAccessException e) {
+                       throw new IllegalStateException(e);
+               } catch (InvocationTargetException e) {
+                       throw new IllegalStateException(e);
+               }
+
+       }
+
+       @Override
+       public void visit(NodeValue nv) {
+               NodeValueRewriter rewriter = new NodeValueRewriter(values);
+               nv.visit(rewriter);
+               push(rewriter.pop());
+       }
+
+       @Override
+       public void visit(ExprVar nv) {
+               Node n = changeNode(nv.asVar());
+               if (n.isVariable()) {
+                       push(new ExprVar(n));
+               } else {
+                       push(NodeValue.makeNode(n));
+               }
+       }
+
+       @Override
+       public void visit(ExprAggregator eAgg) {
+               Node n = changeNode(eAgg.getVar());
+               if (n.equals(eAgg.getVar())) {
+                       push(eAgg);
+               } else {
+                       push(NodeValue.makeNode(n));
+               }
+
+       }
+
+       @Override
+       public void finishVisit() {
+               // TODO Auto-generated method stub
+
+       }
+
+       public final List<SortCondition> rewriteSortConditionList(
+                       List<SortCondition> lst) {
+               if (lst == null) {
+                       return null;
+               }
+               List<SortCondition> retval = new ArrayList<SortCondition>();
+               for (SortCondition sc : lst) {
+                       retval.add(rewrite(sc));
+               }
+               return retval;
+       }
+
+       public final SortCondition rewrite(SortCondition sortCondition) {
+               sortCondition.getExpression().visit(this);
+               return new SortCondition(pop(), sortCondition.getDirection());
+       }
+
+       public final ExprList rewrite(ExprList lst) {
+               if (lst == null) {
+                       return null;
+               }
+               ExprList exprList = new ExprList();
+               int limit = lst.size();
+               for (int i = 0; i < limit; i++) {
+                       lst.get(i).visit(this);
+                       exprList.add(pop());
+               }
+               return exprList;
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/NodeValueRewriter.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/NodeValueRewriter.java
 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/NodeValueRewriter.java
new file mode 100644
index 0000000..8759547
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/NodeValueRewriter.java
@@ -0,0 +1,96 @@
+/*
+ * 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.rewriters;
+
+import java.util.Map;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.expr.NodeValue;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueBoolean;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueDT;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueDecimal;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueDouble;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueDuration;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueFloat;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueInteger;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueNode;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueString;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueVisitor;
+
+/**
+ * A rewriter that implements NoveValueVisitor
+ *
+ */
+class NodeValueRewriter extends AbstractRewriter<NodeValue> implements
+               NodeValueVisitor {
+
+       /**
+        * Constructor.  
+        * @param values The values to replace.
+        */
+       public NodeValueRewriter(Map<Var, Node> values) {
+               super(values);
+       }
+
+       @Override
+       public void visit(NodeValueBoolean nv) {
+               push(new NodeValueBoolean(nv.getBoolean(), 
changeNode(nv.getNode())));
+       }
+
+       @Override
+       public void visit(NodeValueDecimal nv) {
+               push(new NodeValueDecimal(nv.getDecimal(), 
changeNode(nv.getNode())));
+       }
+
+       @Override
+       public void visit(NodeValueDouble nv) {
+               push(new NodeValueDouble(nv.getDouble(), 
changeNode(nv.getNode())));
+       }
+
+       @Override
+       public void visit(NodeValueFloat nv) {
+               push(new NodeValueFloat(nv.getFloat(), 
changeNode(nv.getNode())));
+       }
+
+       @Override
+       public void visit(NodeValueInteger nv) {
+               push(new NodeValueInteger(nv.getInteger(), 
changeNode(nv.getNode())));
+       }
+
+       @Override
+       public void visit(NodeValueNode nv) {
+               push(new NodeValueNode(changeNode(nv.getNode())));
+       }
+
+       @Override
+       public void visit(NodeValueString nv) {
+               push(new NodeValueString(nv.getString(), 
changeNode(nv.getNode())));
+       }
+
+       @Override
+       public void visit(NodeValueDT nv) {
+               push(new NodeValueDT(nv.getDateTime().toXMLFormat(),
+                               changeNode(nv.getNode())));
+       }
+
+       @Override
+       public void visit(NodeValueDuration nodeValueDuration) {
+               push(new NodeValueDuration(nodeValueDuration.getDuration(),
+                               changeNode(nodeValueDuration.getNode())));
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/OpRewriter.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/OpRewriter.java
 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/OpRewriter.java
new file mode 100644
index 0000000..b0eb8e6
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/OpRewriter.java
@@ -0,0 +1,368 @@
+/*
+ * 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.rewriters;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.query.SortCondition;
+import com.hp.hpl.jena.sparql.algebra.Op;
+import com.hp.hpl.jena.sparql.algebra.OpVisitor;
+import com.hp.hpl.jena.sparql.algebra.Table;
+import com.hp.hpl.jena.sparql.algebra.op.OpAssign;
+import com.hp.hpl.jena.sparql.algebra.op.OpBGP;
+import com.hp.hpl.jena.sparql.algebra.op.OpConditional;
+import com.hp.hpl.jena.sparql.algebra.op.OpDatasetNames;
+import com.hp.hpl.jena.sparql.algebra.op.OpDiff;
+import com.hp.hpl.jena.sparql.algebra.op.OpDisjunction;
+import com.hp.hpl.jena.sparql.algebra.op.OpDistinct;
+import com.hp.hpl.jena.sparql.algebra.op.OpExt;
+import com.hp.hpl.jena.sparql.algebra.op.OpExtend;
+import com.hp.hpl.jena.sparql.algebra.op.OpFilter;
+import com.hp.hpl.jena.sparql.algebra.op.OpGraph;
+import com.hp.hpl.jena.sparql.algebra.op.OpGroup;
+import com.hp.hpl.jena.sparql.algebra.op.OpJoin;
+import com.hp.hpl.jena.sparql.algebra.op.OpLabel;
+import com.hp.hpl.jena.sparql.algebra.op.OpLeftJoin;
+import com.hp.hpl.jena.sparql.algebra.op.OpList;
+import com.hp.hpl.jena.sparql.algebra.op.OpMinus;
+import com.hp.hpl.jena.sparql.algebra.op.OpNull;
+import com.hp.hpl.jena.sparql.algebra.op.OpOrder;
+import com.hp.hpl.jena.sparql.algebra.op.OpPath;
+import com.hp.hpl.jena.sparql.algebra.op.OpProcedure;
+import com.hp.hpl.jena.sparql.algebra.op.OpProject;
+import com.hp.hpl.jena.sparql.algebra.op.OpPropFunc;
+import com.hp.hpl.jena.sparql.algebra.op.OpQuad;
+import com.hp.hpl.jena.sparql.algebra.op.OpQuadBlock;
+import com.hp.hpl.jena.sparql.algebra.op.OpQuadPattern;
+import com.hp.hpl.jena.sparql.algebra.op.OpReduced;
+import com.hp.hpl.jena.sparql.algebra.op.OpSequence;
+import com.hp.hpl.jena.sparql.algebra.op.OpService;
+import com.hp.hpl.jena.sparql.algebra.op.OpSlice;
+import com.hp.hpl.jena.sparql.algebra.op.OpTable;
+import com.hp.hpl.jena.sparql.algebra.op.OpTopN;
+import com.hp.hpl.jena.sparql.algebra.op.OpTriple;
+import com.hp.hpl.jena.sparql.algebra.op.OpUnion;
+import com.hp.hpl.jena.sparql.algebra.table.TableN;
+import com.hp.hpl.jena.sparql.core.BasicPattern;
+import com.hp.hpl.jena.sparql.core.Quad;
+import com.hp.hpl.jena.sparql.core.QuadPattern;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.core.VarExprList;
+import com.hp.hpl.jena.sparql.engine.binding.Binding;
+import com.hp.hpl.jena.sparql.expr.ExprAggregator;
+import com.hp.hpl.jena.sparql.expr.ExprList;
+import com.hp.hpl.jena.sparql.pfunction.PropFuncArg;
+
+/**
+ * A rewriter that implements OpVisitor.
+ *
+ */
+class OpRewriter extends AbstractRewriter<Op> implements OpVisitor {
+
+       /**
+        * Constructor.
+        * @param values The values to replace.
+        */
+       OpRewriter(Map<Var, Node> values) {
+               super(values);
+       }
+
+       private Quad rewrite(Quad q) {
+               return new Quad(changeNode(q.getGraph()), 
changeNode(q.getSubject()),
+                               changeNode(q.getPredicate()), 
changeNode(q.getObject()));
+       }
+
+       private QuadPattern rewrite(QuadPattern pattern) {
+               QuadPattern qp = new QuadPattern();
+               for (Quad q : pattern.getList()) {
+                       qp.add(rewrite(q));
+               }
+               return qp;
+       }
+
+       private List<Op> rewriteOpList(List<Op> lst) {
+               List<Op> retval = new ArrayList<Op>();
+               for (Op o : lst) {
+                       o.visit(this);
+                       retval.add(pop());
+               }
+               return retval;
+       }
+
+       private BasicPattern rewrite(BasicPattern pattern) {
+               return BasicPattern.wrap(rewrite(pattern.getList()));
+       }
+
+       @Override
+       public void visit(OpBGP opBGP) {
+               push(new OpBGP(rewrite(opBGP.getPattern())));
+       }
+
+       @Override
+       public void visit(OpQuadPattern quadPattern) {
+               push(new OpQuadPattern(changeNode(quadPattern.getGraphNode()),
+                               rewrite(quadPattern.getBasicPattern())));
+       }
+
+       @Override
+       public void visit(OpQuadBlock quadBlock) {
+               push(new OpQuadBlock(rewrite(quadBlock.getPattern())));
+       }
+
+       @Override
+       public void visit(OpTriple opTriple) {
+               push(new OpTriple(rewrite(opTriple.getTriple())));
+       }
+
+       @Override
+       public void visit(OpQuad opQuad) {
+               push(new OpQuad(rewrite(opQuad.getQuad())));
+
+       }
+
+       @Override
+       public void visit(OpPath opPath) {
+               push(new OpPath(rewrite(opPath.getTriplePath())));
+       }
+
+       @Override
+       public void visit(OpTable opTable) {
+               Table tbl = opTable.getTable();
+               boolean process = false;
+               for (Var v : tbl.getVars()) {
+                       process = process | values.keySet().contains(v);
+               }
+               if (!process) {
+                       push(opTable);
+               } else {
+                       TableN retTbl = new TableN(tbl.getVars());
+                       Iterator<Binding> iter = tbl.rows();
+                       while (iter.hasNext()) {
+                               retTbl.addBinding(rewrite(iter.next()));
+                       }
+                       push(OpTable.create(retTbl));
+               }
+       }
+
+       @Override
+       public void visit(OpNull opNull) {
+               push(opNull);
+       }
+
+       @Override
+       public void visit(OpProcedure opProc) {
+               opProc.getSubOp().visit(this);
+               Op op = pop();
+               ExprList args = new 
ExprRewriter(values).rewrite(opProc.getArgs());
+               Node procId = changeNode(opProc.getProcId());
+               push(new OpProcedure(procId, args, op));
+       }
+
+       private PropFuncArg rewrite(PropFuncArg arg) {
+               if (arg.isList()) {
+                       List<Node> lst = changeNodes(arg.getArgList());
+                       return new PropFuncArg(lst, null);
+               }
+               return new PropFuncArg(changeNode(arg.getArg()));
+       }
+
+       @Override
+       public void visit(OpPropFunc opPropFunc) {
+               opPropFunc.getSubOp().visit(this);
+               Op op = pop();
+               Node uri = changeNode(opPropFunc.getProperty());
+               PropFuncArg args1 = rewrite(opPropFunc.getSubjectArgs());
+               PropFuncArg args2 = rewrite(opPropFunc.getObjectArgs());
+               push(new OpPropFunc(uri, args1, args2, op));
+       }
+
+       @Override
+       public void visit(OpFilter opFilter) {
+               opFilter.getSubOp().visit(this);
+               push(OpFilter.filter(
+                               new 
ExprRewriter(values).rewrite(opFilter.getExprs()), pop()));
+       }
+
+       @Override
+       public void visit(OpGraph opGraph) {
+               opGraph.getSubOp().visit(this);
+               push(new OpGraph(changeNode(opGraph.getNode()), pop()));
+       }
+
+       @Override
+       public void visit(OpService opService) {
+               opService.getSubOp().visit(this);
+               push(new OpService(changeNode(opService.getService()), pop(),
+                               opService.getSilent()));
+       }
+
+       @Override
+       public void visit(OpDatasetNames dsNames) {
+               push(new OpDatasetNames(changeNode(dsNames.getGraphNode())));
+       }
+
+       @Override
+       public void visit(OpLabel opLabel) {
+               if (opLabel.hasSubOp()) {
+                       opLabel.getSubOp().visit(this);
+                       push(OpLabel.create(opLabel.getObject(), pop()));
+               } else {
+                       push(opLabel);
+               }
+       }
+
+       @Override
+       public void visit(OpAssign opAssign) {
+               opAssign.getSubOp().visit(this);
+               push(OpAssign.assign(pop(), 
rewrite(opAssign.getVarExprList())));
+       }
+
+       @Override
+       public void visit(OpExtend opExtend) {
+               opExtend.getSubOp().visit(this);
+               push(OpExtend.extend(pop(), 
rewrite(opExtend.getVarExprList())));
+       }
+
+       @Override
+       public void visit(OpJoin opJoin) {
+               opJoin.getRight().visit(this);
+               opJoin.getLeft().visit(this);
+               push(OpJoin.create(pop(), pop()));
+       }
+
+       @Override
+       public void visit(OpLeftJoin opLeftJoin) {
+               opLeftJoin.getRight().visit(this);
+               opLeftJoin.getLeft().visit(this);
+               push(OpLeftJoin.create(pop(), pop(),
+                               new 
ExprRewriter(values).rewrite(opLeftJoin.getExprs())));
+       }
+
+       @Override
+       public void visit(OpUnion opUnion) {
+               opUnion.getRight().visit(this);
+               opUnion.getLeft().visit(this);
+               push(OpUnion.create(pop(), pop()));
+       }
+
+       @Override
+       public void visit(OpDiff opDiff) {
+               opDiff.getRight().visit(this);
+               opDiff.getLeft().visit(this);
+               push(OpDiff.create(pop(), pop()));
+       }
+
+       @Override
+       public void visit(OpMinus opMinus) {
+               opMinus.getRight().visit(this);
+               opMinus.getLeft().visit(this);
+               push(OpMinus.create(pop(), pop()));
+       }
+
+       @Override
+       public void visit(OpConditional opCondition) {
+               opCondition.getRight().visit(this);
+               opCondition.getLeft().visit(this);
+               push(new OpConditional(pop(), pop()));
+       }
+
+       @Override
+       public void visit(OpSequence opSequence) {
+               List<Op> lst = rewriteOpList(opSequence.getElements());
+               push(opSequence.copy(lst));
+       }
+
+       @Override
+       public void visit(OpDisjunction opDisjunction) {
+               List<Op> lst = rewriteOpList(opDisjunction.getElements());
+               push(opDisjunction.copy(lst));
+       }
+
+       @Override
+       public void visit(OpExt opExt) {
+               push(opExt);
+       }
+
+       @Override
+       public void visit(OpList opList) {
+               opList.getSubOp().visit(this);
+               push(new OpList(pop()));
+       }
+
+       @Override
+       public void visit(OpOrder opOrder) {
+               List<SortCondition> lst = new ExprRewriter(values)
+                               
.rewriteSortConditionList(opOrder.getConditions());
+               opOrder.getSubOp().visit(this);
+               push(new OpOrder(pop(), lst));
+       }
+
+       @Override
+       public void visit(OpProject opProject) {
+               opProject.getSubOp().visit(this);
+               List<Var> vars = new ArrayList<Var>();
+               for (Var v : opProject.getVars()) {
+                       Node n = changeNode(v);
+                       vars.add(Var.alloc(n));
+               }
+               push(new OpProject(pop(), vars));
+       }
+
+       @Override
+       public void visit(OpReduced opReduced) {
+               opReduced.getSubOp().visit(this);
+               push(opReduced.copy(pop()));
+       }
+
+       @Override
+       public void visit(OpDistinct opDistinct) {
+               opDistinct.getSubOp().visit(this);
+               push(opDistinct.copy(pop()));
+       }
+
+       @Override
+       public void visit(OpSlice opSlice) {
+               opSlice.getSubOp().visit(this);
+               push(opSlice.copy(pop()));
+       }
+
+       @Override
+       public void visit(OpGroup opGroup) {
+               opGroup.getSubOp().visit(this);
+               ExprRewriter expRewriter = new ExprRewriter(values);
+               VarExprList groupVars = rewrite(opGroup.getGroupVars());
+               List<ExprAggregator> aggregators = new 
ArrayList<ExprAggregator>();
+               for (ExprAggregator ea : opGroup.getAggregators()) {
+                       ea.visit(expRewriter);
+                       aggregators.add((ExprAggregator) expRewriter.pop());
+               }
+               push(new OpGroup(pop(), groupVars, aggregators));
+       }
+
+       @Override
+       public void visit(OpTopN opTop) {
+               opTop.getSubOp().visit(this);
+               ExprRewriter expRewriter = new ExprRewriter(values);
+               expRewriter.rewriteSortConditionList(opTop.getConditions());
+               push(new OpTopN(pop(), opTop.getLimit(),
+                               
expRewriter.rewriteSortConditionList(opTop.getConditions())));
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/PathRewriter.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/PathRewriter.java
 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/PathRewriter.java
new file mode 100644
index 0000000..95742fb
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/PathRewriter.java
@@ -0,0 +1,163 @@
+/*
+ * 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.rewriters;
+
+import java.util.Map;
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.path.P_Alt;
+import com.hp.hpl.jena.sparql.path.P_Distinct;
+import com.hp.hpl.jena.sparql.path.P_FixedLength;
+import com.hp.hpl.jena.sparql.path.P_Inverse;
+import com.hp.hpl.jena.sparql.path.P_Link;
+import com.hp.hpl.jena.sparql.path.P_Mod;
+import com.hp.hpl.jena.sparql.path.P_Multi;
+import com.hp.hpl.jena.sparql.path.P_NegPropSet;
+import com.hp.hpl.jena.sparql.path.P_OneOrMore1;
+import com.hp.hpl.jena.sparql.path.P_OneOrMoreN;
+import com.hp.hpl.jena.sparql.path.P_Path0;
+import com.hp.hpl.jena.sparql.path.P_ReverseLink;
+import com.hp.hpl.jena.sparql.path.P_Seq;
+import com.hp.hpl.jena.sparql.path.P_Shortest;
+import com.hp.hpl.jena.sparql.path.P_ZeroOrMore1;
+import com.hp.hpl.jena.sparql.path.P_ZeroOrMoreN;
+import com.hp.hpl.jena.sparql.path.P_ZeroOrOne;
+import com.hp.hpl.jena.sparql.path.Path;
+import com.hp.hpl.jena.sparql.path.PathVisitor;
+
+/**
+ * A rewriter that implements PathVisitor.
+ *
+ */
+public class PathRewriter extends AbstractRewriter<Path> implements 
PathVisitor {
+
+       /**
+        * Constructor.
+        * @param values The values to replace.
+        */
+       public PathRewriter(Map<Var, Node> values) {
+               super(values);
+       }
+
+       @Override
+       public void visit(P_Link pathNode) {
+               push(new P_Link(changeNode(pathNode.getNode())));
+       }
+
+       @Override
+       public void visit(P_ReverseLink pathNode) {
+               push(new P_ReverseLink(changeNode(pathNode.getNode())));
+       }
+
+       /*
+        * Reverse transformations. X !(^:uri1|...|^:urin)Y ==> ^(X
+        * !(:uri1|...|:urin) Y) Split into forward and reverse. X
+        * !(:uri1|...|:urii|^:urii+1|...|^:urim) Y ==> { X 
!(:uri1|...|:urii|)Y }
+        * UNION { X !(^:urii+1|...|^:urim) Y }
+        */
+       @Override
+       public void visit(P_NegPropSet pathNotOneOf) {
+               P_NegPropSet retval = new P_NegPropSet();
+
+               for (Path p : pathNotOneOf.getNodes()) {
+                       p.visit(this);
+                       retval.add((P_Path0) pop());
+               }
+               push(retval);
+       }
+
+       @Override
+       public void visit(P_Inverse inversePath) {
+               inversePath.getSubPath().visit(this);
+               push(new P_Inverse(pop()));
+       }
+
+       @Override
+       public void visit(P_Mod pathMod) {
+               pathMod.getSubPath().visit(this);
+               push(new P_Mod(pop(), pathMod.getMin(), pathMod.getMax()));
+       }
+
+       @Override
+       public void visit(P_FixedLength pFixedLength) {
+               pFixedLength.getSubPath().visit(this);
+               push(new P_FixedLength(pop(), pFixedLength.getCount()));
+       }
+
+       @Override
+       public void visit(P_Alt pathAlt) {
+               pathAlt.getRight().visit(this);
+               pathAlt.getLeft().visit(this);
+               push(new P_Alt(pop(), pop()));
+       }
+
+       @Override
+       public void visit(P_Seq pathSeq) {
+               pathSeq.getRight().visit(this);
+               pathSeq.getLeft().visit(this);
+               push(new P_Seq(pop(), pop()));
+       }
+
+       @Override
+       public void visit(P_Distinct pathDistinct) {
+               pathDistinct.getSubPath().visit(this);
+               push(new P_Distinct(pop()));
+       }
+
+       @Override
+       public void visit(P_Multi pathMulti) {
+               pathMulti.getSubPath().visit(this);
+               push(new P_Multi(pop()));
+       }
+
+       @Override
+       public void visit(P_Shortest pathShortest) {
+               pathShortest.getSubPath().visit(this);
+               push(new P_Shortest(pop()));
+       }
+
+       @Override
+       public void visit(P_ZeroOrOne path) {
+               path.getSubPath().visit(this);
+               push(new P_ZeroOrOne(pop()));
+       }
+
+       @Override
+       public void visit(P_ZeroOrMore1 path) {
+               path.getSubPath().visit(this);
+               push(new P_ZeroOrMore1(pop()));
+       }
+
+       @Override
+       public void visit(P_ZeroOrMoreN path) {
+               path.getSubPath().visit(this);
+               push(new P_ZeroOrMoreN(pop()));
+       }
+
+       @Override
+       public void visit(P_OneOrMore1 path) {
+               path.getSubPath().visit(this);
+               push(new P_OneOrMore1(pop()));
+       }
+
+       @Override
+       public void visit(P_OneOrMoreN path) {
+               path.getSubPath().visit(this);
+               push(new P_OneOrMoreN(pop()));
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/package-info.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/package-info.java
 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/package-info.java
new file mode 100644
index 0000000..b548b7e
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/rewriters/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * Classes to rewrite Query algebra, expressions and other objects to handle 
variable replacement for 
+ * the prepared statement functionality.
+ * 
+ * In most cases developers will not need to access the rewriteres directly.
+ */
+package org.apache.jena.arq.querybuilder.rewriters;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/AbstractRegexpBasedTest.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/AbstractRegexpBasedTest.java
 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/AbstractRegexpBasedTest.java
new file mode 100644
index 0000000..7190707
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/AbstractRegexpBasedTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.regex.Pattern;
+
+public abstract class AbstractRegexpBasedTest {
+       protected static final String SPACE = "\\s+";
+       protected static final String OPT_SPACE = "\\s*";
+       protected static final String WHERE = "WHERE" + SPACE;
+       protected static final String OPEN_CURLY = "\\{" + OPT_SPACE;
+       protected static final String CLOSE_CURLY = OPT_SPACE + "\\}";
+       protected static final String OPEN_PAREN = "\\(" + OPT_SPACE;
+       protected static final String CLOSE_PAREN = OPT_SPACE + "\\)";
+       protected static final String QUOTE = "\\\"";
+       protected static final String LT = "\\<";
+       protected static final String GT = "\\>";
+       protected static final String DOT = "\\.";
+       protected static final String ORDER_BY = "ORDER" + SPACE + "BY" + SPACE;
+       protected static final String GROUP_BY = "GROUP" + SPACE + "BY" + SPACE;
+       protected static final String HAVING = "HAVING" + SPACE;
+       protected static final String PREFIX = "PREFIX" + SPACE;
+       protected static final String SELECT = "SELECT" + SPACE;
+       protected static final String UNION = "UNION" + SPACE;
+       protected static final String LIMIT = "LIMIT" + SPACE;
+       protected static final String OFFSET = "OFFSET" + SPACE;
+       protected static final String OPTIONAL = "OPTIONAL" + SPACE;
+
+       protected final String quote(String s) {
+               return String.format("%s%s%s", QUOTE, s, QUOTE);
+       }
+
+       protected final String node(String s) {
+               return String.format("%s%s%s", LT, s, GT);
+       }
+
+       protected final String var(String s) {
+               return "\\?" + s;
+       }
+
+       protected final void assertNotContainsRegex(String expected, String 
lst) {
+
+               Pattern patt = Pattern.compile(expected, Pattern.DOTALL);
+
+               if (patt.matcher(lst).find()) {
+                       fail(String.format("%s was found in %s", expected, 
lst));
+               }
+       }
+
+       protected final void assertContainsRegex(String expected, String entry) 
{
+
+               Pattern patt = Pattern.compile(expected, Pattern.DOTALL);
+               if (patt.matcher(entry).find()) {
+                       return;
+               }
+               fail(String.format("%s not found in %s", expected, entry));
+       }
+
+       protected final void assertNotContainsRegex(String expected, String[] 
lst) {
+
+               Pattern patt = Pattern.compile(expected, Pattern.DOTALL);
+               for (String s : lst) {
+                       if (patt.matcher(s).find()) {
+                               fail(String.format("%s was found in %s", 
expected,
+                                               Arrays.asList(lst)));
+                       }
+               }
+       }
+
+       protected final void assertContainsRegex(String expected, String[] lst) 
{
+
+               Pattern patt = Pattern.compile(expected, Pattern.DOTALL);
+               for (String s : lst) {
+                       if (patt.matcher(s).find()) {
+                               return;
+                       }
+               }
+               fail(String.format("%s not found in %s", expected, 
Arrays.asList(lst)));
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilderTest.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilderTest.java
 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilderTest.java
new file mode 100644
index 0000000..b0ce2aa
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilderTest.java
@@ -0,0 +1,108 @@
+package org.apache.jena.arq.querybuilder;
+
+import static org.junit.Assert.*;
+
+import org.junit.Before;
+import org.junit.Test;
+
+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.LiteralLabel;
+import com.hp.hpl.jena.graph.impl.LiteralLabelFactory;
+import com.hp.hpl.jena.reasoner.rulesys.Node_RuleVariable;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.expr.ExprVar;
+import com.hp.hpl.jena.vocabulary.RDF;
+
+public class AbstractQueryBuilderTest {
+
+       private AbstractQueryBuilder<?> builder;
+
+       @Before
+       public void setup() {
+               builder = new TestBuilder();
+       }
+
+       private class TestBuilder extends AbstractQueryBuilder<TestBuilder> {
+               @Override
+               public String toString() {
+                       return "TestBuilder";
+               }
+       }
+
+       private class NodeFront implements FrontsNode {
+               Node n;
+
+               NodeFront(Node n) {
+                       this.n = n;
+               }
+
+               @Override
+               public Node asNode() {
+                       return n;
+               }
+       }
+
+       @Test
+       public void testMakeNode() {
+               Node n = builder.makeNode(null);
+               assertEquals(Node.ANY, n);
+
+               n = builder.makeNode(RDF.type);
+               assertEquals(RDF.type.asNode(), n);
+
+               Node n2 = NodeFactory.createAnon();
+               n = builder.makeNode(n2);
+               assertEquals(n2, n);
+
+               builder.addPrefix("demo", "http://example.com/";);
+               n = builder.makeNode("demo:type");
+               assertEquals(NodeFactory.createURI("http://example.com/type";), 
n);
+
+               n = builder.makeNode("<one>");
+               assertEquals(NodeFactory.createURI("one"), n);
+
+               n = builder.makeNode(builder);
+               LiteralLabel ll = LiteralLabelFactory.create(builder);
+               assertEquals(NodeFactory.createLiteral(ll), n);
+
+       }
+
+       @Test
+       public void testMakeVar() {
+               Var v = builder.makeVar(null);
+               assertEquals(Var.ANON, v);
+
+               v = builder.makeVar("a");
+               assertEquals(Var.alloc("a"), v);
+
+               v = builder.makeVar("?a");
+               assertEquals(Var.alloc("a"), v);
+
+               Node n = NodeFactory.createVariable("foo");
+               v = builder.makeVar(n);
+               assertEquals(Var.alloc("foo"), v);
+
+               NodeFront nf = new NodeFront(n);
+               v = builder.makeVar(nf);
+               assertEquals(Var.alloc("foo"), v);
+
+               v = builder.makeVar(Node_RuleVariable.WILD);
+               assertNull(v);
+
+               ExprVar ev = new ExprVar("bar");
+               v = builder.makeVar(ev);
+               assertEquals(Var.alloc("bar"), v);
+
+               ev = new ExprVar(n);
+               v = builder.makeVar(ev);
+               assertEquals(Var.alloc("foo"), v);
+
+               ev = new ExprVar(Var.ANON);
+               v = builder.makeVar(ev);
+               assertEquals(Var.ANON, v);
+
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AskBuilderContractTest.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AskBuilderContractTest.java
 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AskBuilderContractTest.java
new file mode 100644
index 0000000..7fd6af5
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/AskBuilderContractTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.junit.runner.RunWith;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractImpl;
+import org.xenei.junit.contract.ContractSuite;
+import org.xenei.junit.contract.IProducer;
+
+@RunWith(ContractSuite.class)
+@ContractImpl(AskBuilder.class)
+public class AskBuilderContractTest {
+
+       // create the producer to inject
+       private IProducer<AskBuilder> producer = new IProducer<AskBuilder>() {
+
+               @Override
+               public AskBuilder newInstance() {
+                       return new AskBuilder();
+               }
+
+               @Override
+               public void cleanUp() {
+                       // no cleanup required
+               }
+
+       };
+
+       public AskBuilderContractTest() {
+       }
+
+       @Contract.Inject
+       public IProducer<AskBuilder> getProducer() {
+               return producer;
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConstructBuilderContractTest.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConstructBuilderContractTest.java
 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConstructBuilderContractTest.java
new file mode 100644
index 0000000..f1c68bd
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/ConstructBuilderContractTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.junit.runner.RunWith;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractImpl;
+import org.xenei.junit.contract.ContractSuite;
+import org.xenei.junit.contract.IProducer;
+
+@RunWith(ContractSuite.class)
+@ContractImpl(ConstructBuilder.class)
+public class ConstructBuilderContractTest {
+
+       // create the producer to inject
+       private IProducer<ConstructBuilder> producer = new 
IProducer<ConstructBuilder>() {
+
+               @Override
+               public ConstructBuilder newInstance() {
+                       return new ConstructBuilder();
+               }
+
+               @Override
+               public void cleanUp() {
+                       // no cleanup required
+               }
+
+       };
+
+       public ConstructBuilderContractTest() {
+       }
+
+       @Contract.Inject
+       public IProducer<ConstructBuilder> getProducer() {
+               return producer;
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderContractTest.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderContractTest.java
 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderContractTest.java
new file mode 100644
index 0000000..0ff0701
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderContractTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.junit.runner.RunWith;
+import org.xenei.junit.contract.Contract;
+import org.xenei.junit.contract.ContractImpl;
+import org.xenei.junit.contract.ContractSuite;
+import org.xenei.junit.contract.IProducer;
+
+@RunWith(ContractSuite.class)
+@ContractImpl(SelectBuilder.class)
+public class SelectBuilderContractTest {
+
+       // create the producer to inject
+       private IProducer<SelectBuilder> producer = new 
IProducer<SelectBuilder>() {
+
+               @Override
+               public SelectBuilder newInstance() {
+                       return new SelectBuilder();
+               }
+
+               @Override
+               public void cleanUp() {
+                       // no cleanup required
+               }
+
+       };
+
+       public SelectBuilderContractTest() {
+       }
+
+       @Contract.Inject
+       public IProducer<SelectBuilder> getProducer() {
+               return producer;
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderTest.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderTest.java
 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderTest.java
new file mode 100644
index 0000000..d9de0b4
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/SelectBuilderTest.java
@@ -0,0 +1,114 @@
+package org.apache.jena.arq.querybuilder;
+
+import org.apache.jena.arq.AbstractRegexpBasedTest;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.vocabulary.RDF;
+
+public class SelectBuilderTest extends AbstractRegexpBasedTest {
+
+       private SelectBuilder builder;
+
+       @Before
+       public void setup() {
+               builder = new SelectBuilder();
+       }
+
+       @Test
+       public void testSelectAsterisk() {
+               builder.addVar("*").addWhere("?s", "?p", "?o");
+
+               assertContainsRegex(SELECT + "\\*" + SPACE + WHERE + OPEN_CURLY
+                               + var("s") + SPACE + var("p") + SPACE + 
var("o") + OPT_SPACE
+                               + DOT + CLOSE_CURLY, builder.buildString());
+
+               builder.setVar(Var.alloc("p"), RDF.type);
+
+               assertContainsRegex(SELECT + "\\*" + SPACE + WHERE + OPEN_CURLY
+                               + var("s") + SPACE
+                               + 
node("http://www.w3.org/1999/02/22-rdf-syntax-ns#type";)
+                               + SPACE + var("o") + OPT_SPACE + DOT + 
CLOSE_CURLY,
+                               builder.buildString());
+       }
+
+       @Test
+       public void testAll() {
+               builder.addVar("s").addPrefix("foaf", 
"http://xmlns.com/foaf/0.1/";)
+                               .addWhere("?s", RDF.type, "foaf:Person")
+                               .addOptional("?s", "foaf:name", 
"?name").addOrderBy("?s");
+
+               String query = builder.buildString();
+               /*
+                * PREFIX foaf: <http://xmlns.com/foaf/0.1/>
+                * 
+                * SELECT ?s WHERE { ?s
+                * <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> 
foaf:Person .
+                * OPTIONAL { ?s foaf:name ?name .} } ORDER BY ?s
+                */
+               assertContainsRegex(PREFIX + "foaf:" + SPACE
+                               + node("http://xmlns.com/foaf/0.1/";), query);
+               assertContainsRegex(SELECT + var("s"), query);
+               assertContainsRegex(WHERE + OPEN_CURLY + var("s") + SPACE
+                               + 
node("http://www.w3.org/1999/02/22-rdf-syntax-ns#type";)
+                               + SPACE + "foaf:Person" + OPT_SPACE + DOT + 
SPACE + OPTIONAL
+                               + OPEN_CURLY + var("s") + SPACE + "foaf:name" + 
SPACE
+                               + var("name") + SPACE + DOT + OPT_SPACE + 
CLOSE_CURLY
+                               + CLOSE_CURLY, query);
+               assertContainsRegex(ORDER_BY + var("s"), query);
+
+               builder.setVar("name", "Smith");
+
+               query = builder.buildString();
+               assertContainsRegex(PREFIX + "foaf:" + SPACE
+                               + node("http://xmlns.com/foaf/0.1/";), query);
+               assertContainsRegex(SELECT + var("s"), query);
+               assertContainsRegex(WHERE + OPEN_CURLY + var("s") + SPACE
+                               + 
node("http://www.w3.org/1999/02/22-rdf-syntax-ns#type";)
+                               + SPACE + "foaf:Person" + OPT_SPACE + DOT + 
SPACE + OPTIONAL
+                               + OPEN_CURLY + var("s") + SPACE + "foaf:name" + 
SPACE
+                               + quote("Smith") + "\\^\\^"
+                               + 
node("http://www.w3.org/2001/XMLSchema#string";) + SPACE + DOT
+                               + OPT_SPACE + CLOSE_CURLY + CLOSE_CURLY, query);
+               assertContainsRegex(ORDER_BY + var("s"), query);
+       }
+
+       @Test
+       public void testPredicateVar() {
+               builder.addVar("*").addPrefix("", "http://example/";)
+                               .addWhere(":S", "?p", ":O");
+               String query = builder.buildString();
+
+               assertContainsRegex(WHERE + OPEN_CURLY + ":S" + SPACE + var("p")
+                               + SPACE + ":O" + OPT_SPACE + DOT + CLOSE_CURLY, 
query);
+       }
+
+       @Test
+       public void testSubjectVar() {
+               builder.addVar("*").addPrefix("", "http://example/";)
+                               .addWhere("?s", ":P", ":O");
+               String query = builder.buildString();
+
+               assertContainsRegex(WHERE + OPEN_CURLY + var("s") + SPACE + ":P"
+                               + SPACE + ":O" + OPT_SPACE + DOT + CLOSE_CURLY, 
query);
+       }
+
+       @Test
+       public void testObjectVar() {
+               builder.addVar("*").addPrefix("", "http://example/";)
+                               .addWhere(":S", ":P", "?o");
+               String query = builder.buildString();
+
+               assertContainsRegex(WHERE + OPEN_CURLY + ":S" + SPACE + ":P" + 
SPACE
+                               + var("o") + OPT_SPACE + DOT +  CLOSE_CURLY, 
query);
+       }
+
+       @Test
+       public void testNoVars() {
+               builder.addWhere("?s", "?p", "?o");
+               String query = builder.buildString();
+
+               assertContainsRegex(SELECT + "\\*" + SPACE, query);
+       }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/2fb788d3/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/AbstractClauseTest.java
----------------------------------------------------------------------
diff --git 
a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/AbstractClauseTest.java
 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/AbstractClauseTest.java
new file mode 100644
index 0000000..f33a1e4
--- /dev/null
+++ 
b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/AbstractClauseTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.jena.arq.AbstractRegexpBasedTest;
+import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
+
+import com.hp.hpl.jena.query.Query;
+
+public abstract class AbstractClauseTest extends AbstractRegexpBasedTest {
+
+       protected final String[] byLine(AbstractQueryBuilder<?> builder) {
+               return builder.buildString().split("\n");
+       }
+
+       protected final Query getQuery(AbstractQueryBuilder<?> builder)
+                       throws NoSuchFieldException, SecurityException,
+                       IllegalArgumentException, IllegalAccessException {
+               Field f = AbstractQueryBuilder.class.getDeclaredField("query");
+               f.setAccessible(true);
+               return (Query) f.get(builder);
+       }
+
+       protected final void assertContains(String expected, String[] lst) {
+               List<String> s = Arrays.asList(lst);
+               assertTrue(String.format("%s not found in %s", expected, s),
+                               s.contains(expected));
+       }
+
+       protected final void assertNotContains(String expected, String[] lst) {
+               List<String> s = Arrays.asList(lst);
+               assertFalse(String.format("%s found in %s", expected, s),
+                               s.contains(expected));
+       }
+
+}

Reply via email to