jena-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cla...@apache.org
Subject [48/51] [partial] added missing querybuilder code.
Date Wed, 15 Oct 2014 18:42:25 GMT
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));
+	}
+
+}


Mime
View raw message