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)); + } + +}
