diff --git a/jena-arq/src/main/java/org/apache/jena/riot/lang/LangEngine.java b/jena-arq/src/main/java/org/apache/jena/riot/lang/LangEngine.java index bf698fda349..25a2d3903e2 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/lang/LangEngine.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/lang/LangEngine.java @@ -20,9 +20,9 @@ import static org.apache.jena.riot.tokens.TokenType.EOF ; import static org.apache.jena.riot.tokens.TokenType.NODE ; + import org.apache.jena.atlas.AtlasException ; import org.apache.jena.atlas.iterator.PeekIterator ; -import org.apache.jena.graph.Node ; import org.apache.jena.riot.RiotParseException ; import org.apache.jena.riot.system.ErrorHandler ; import org.apache.jena.riot.system.ParserProfile ; @@ -117,11 +117,11 @@ protected final Token nextToken() } } - protected final Node scopedBNode(Node scopeNode, String label) - { - return profile.getLabelToNode().get(scopeNode, label) ; - } - +// protected final Node scopedBNode(Node scopeNode, String label) +// { +// return profile.getLabelToNode().get(scopeNode, label) ; +// } +// protected final void expectOrEOF(String msg, TokenType tokenType) { // DOT or EOF diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/FactoryRDF.java b/jena-arq/src/main/java/org/apache/jena/riot/system/FactoryRDF.java new file mode 100644 index 00000000000..d2ba8f8848b --- /dev/null +++ b/jena-arq/src/main/java/org/apache/jena/riot/system/FactoryRDF.java @@ -0,0 +1,56 @@ +/* + * 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.riot.system; + +import org.apache.jena.datatypes.RDFDatatype ; +import org.apache.jena.graph.Graph ; +import org.apache.jena.graph.Node ; +import org.apache.jena.graph.Triple ; +import org.apache.jena.sparql.core.DatasetGraph ; +import org.apache.jena.sparql.core.Quad ; + +/** + * Create core RDF objects: {@link Node}s, {@link Triple}s, {@link Quad}s, + * {@link Graph}, {@link DatasetGraph}s. + *

+ */ +public interface FactoryRDF { + // ?? Are these too varied? + public Graph createGraph() ; + // ?? Are these too varied? + public DatasetGraph createDatasetGraph() ; + public Triple createTriple(Node subject, Node predicate, Node object) ; + public Quad createQuad(Node graph, Node subject, Node predicate, Node object) ; + public Node createURI(String uriStr) ; + public Node createTypedLiteral(String lexical, RDFDatatype datatype) ; + public Node createLangLiteral(String lexical, String langTag) ; + public Node createStringLiteral(String lexical) ; + /** Create a blank node */ + public Node createBlankNode() ; + /** Create a blank node with the given string as internal system id */ + public Node createBlankNode(String label) ; + /** Create a blank with the internal system id taken from 128 bit number provided. + */ + public Node createBlankNode(long mostSigBits, long leastSigBits) ; + +// // Object for scope better? +// public Node createBlankNode(Node scope, String label) ; +// // Object for scope better? +// public Node createBlankNode(Node scope) ; +} \ No newline at end of file diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/FactoryRDFCaching.java b/jena-arq/src/main/java/org/apache/jena/riot/system/FactoryRDFCaching.java new file mode 100644 index 00000000000..03982b63fc2 --- /dev/null +++ b/jena-arq/src/main/java/org/apache/jena/riot/system/FactoryRDFCaching.java @@ -0,0 +1,110 @@ +/* + * 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.riot.system; + +import java.util.concurrent.ExecutionException ; + +import org.apache.jena.ext.com.google.common.cache.Cache ; +import org.apache.jena.atlas.lib.cache.CacheInfo ; +import org.apache.jena.datatypes.RDFDatatype ; +import org.apache.jena.datatypes.xsd.XSDDatatype ; +import org.apache.jena.ext.com.google.common.cache.CacheBuilder ; +import org.apache.jena.ext.com.google.common.cache.CacheStats ; +import org.apache.jena.graph.Node ; +import org.apache.jena.riot.RiotException ; +import org.apache.jena.riot.lang.LabelToNode ; +import org.apache.jena.sparql.graph.NodeConst ; + +/** Adds some caching of created nodes - the caching is tuned to RIOT parser usage */ +public class FactoryRDFCaching extends FactoryRDFStd { + public static final int DftNodeCacheSize = 5000 ; + + // Control the setup - for one thread; start size = 50% of full size, no stats + private final Cache cache ; + + public FactoryRDFCaching() { + this(DftNodeCacheSize) ; + } + + public FactoryRDFCaching(int cacheSize) { + super() ; + cache = setCache(cacheSize) ; + } + + private Cache setCache(int cacheSize) { + return CacheBuilder.newBuilder() + .maximumSize(cacheSize) + .initialCapacity(cacheSize/2) + //.recordStats() + .concurrencyLevel(1) + .build() ; + } + + public FactoryRDFCaching(int cacheSize, LabelToNode labelMapping) { + super(labelMapping) ; + cache = setCache(cacheSize) ; + } + + @Override + public Node createURI(String uriStr) { + try { + return cache.get(uriStr, ()->RiotLib.createIRIorBNode(uriStr)) ; + } + catch (ExecutionException e) { + throw new RiotException("Execution exception filling cache <"+uriStr+">", e) ; + } + } + + // A few constants + + @Override + public Node createTypedLiteral(String lexical, RDFDatatype datatype) { + if ( XSDDatatype.XSDinteger.equals(datatype) ) { + switch(lexical) { + case "0" : return NodeConst.nodeZero ; + case "1" : return NodeConst.nodeOne ; + case "2" : return NodeConst.nodeTwo ; + case "-1" : return NodeConst.nodeMinusOne ; + } + // fallthrough. + } else if ( XSDDatatype.XSDboolean.equals(datatype) ) { + switch(lexical) { + case "true" : return NodeConst.nodeTrue ; + case "false" : return NodeConst.nodeFalse ; + } + // fallthrough. + } + return super.createTypedLiteral(lexical, datatype) ; + } + + @Override + public Node createStringLiteral(String lexical) { + if ( lexical.isEmpty() ) + return NodeConst.emptyString ; + return super.createStringLiteral(lexical) ; + } + + public CacheInfo stats() { + CacheStats stats = cache.stats() ; + if ( stats.missCount() == 0 && stats.hitCount() == 0 ) + // Stats not enabled - all counts zero. + return null ; + return new CacheInfo(DftNodeCacheSize, stats) ; + } +} \ No newline at end of file diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/FactoryRDFStd.java b/jena-arq/src/main/java/org/apache/jena/riot/system/FactoryRDFStd.java new file mode 100644 index 00000000000..4d0ca873e19 --- /dev/null +++ b/jena-arq/src/main/java/org/apache/jena/riot/system/FactoryRDFStd.java @@ -0,0 +1,108 @@ +/* + * 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.riot.system; + +import org.apache.jena.datatypes.RDFDatatype ; +import org.apache.jena.graph.Graph ; +import org.apache.jena.graph.Node ; +import org.apache.jena.graph.NodeFactory ; +import org.apache.jena.graph.Triple ; +import org.apache.jena.riot.lang.LabelToNode ; +import org.apache.jena.sparql.core.DatasetGraph ; +import org.apache.jena.sparql.core.DatasetGraphFactory ; +import org.apache.jena.sparql.core.Quad ; +import org.apache.jena.sparql.graph.GraphFactory ; + +public class FactoryRDFStd implements FactoryRDF { + // Needs reset? + private final LabelToNode labelMapping ; + + public FactoryRDFStd() { + this(SyntaxLabels.createLabelToNode()) ; + } + + public FactoryRDFStd(LabelToNode labelMapping) { + this.labelMapping = labelMapping ; + } + + @Override + public Graph createGraph() { + return GraphFactory.createDefaultGraph() ; + } + + @Override + public DatasetGraph createDatasetGraph() { + return DatasetGraphFactory.create(); // createTxnMem() ; + } + + @Override + public Triple createTriple(Node subject, Node predicate, Node object) { + return Triple.create(subject, predicate, object); + } + + @Override + public Quad createQuad(Node graph, Node subject, Node predicate, Node object) { + return Quad.create(graph, subject, predicate, object) ; + } + + @Override + public Node createURI(String uriStr) { + return RiotLib.createIRIorBNode(uriStr) ; + //return NodeFactory.createURI(uriStr) ; + } + + @Override + public Node createTypedLiteral(String lexical, RDFDatatype datatype) { + return NodeFactory.createLiteral(lexical, datatype) ; + } + + @Override + public Node createLangLiteral(String lexical, String langTag) { + return NodeFactory.createLiteral(lexical, langTag) ; + } + + @Override + public Node createStringLiteral(String lexical) { + return NodeFactory.createLiteral(lexical) ; + } + + @Override + public Node createBlankNode(long mostSigBits, long leastSigBits) { + // XXX Style: Do this fast. Guava? Apache commons? Special case for char[32] + // (Eventually, blank node Nodes will have two longs normally.) + return createBlankNode(String.format("%08X%08X", mostSigBits, leastSigBits)) ; + } + + // Fixed scope. + private static Node scope = NodeFactory.createURI("urn:jena:global_scope") ; + // Scope + @Override + public Node createBlankNode(String label) { + //return NodeFactory.createBlankNode(label) ; + return labelMapping.get(scope, label) ; + } + + // Scope + @Override + public Node createBlankNode() { + //return NodeFactory.createBlankNode() ; + return labelMapping.create() ; + } + +} \ No newline at end of file diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfile.java b/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfile.java index 670f691571f..6969991cd2b 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfile.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfile.java @@ -18,12 +18,10 @@ package org.apache.jena.riot.system; - import org.apache.jena.datatypes.RDFDatatype ; import org.apache.jena.graph.Node ; import org.apache.jena.graph.Triple ; import org.apache.jena.iri.IRI ; -import org.apache.jena.riot.lang.LabelToNode ; import org.apache.jena.riot.tokens.Token ; import org.apache.jena.sparql.core.Quad ; @@ -55,21 +53,23 @@ public interface ParserProfile /** Create a fresh blank node */ public Node createBlankNode(Node scope, long line, long col) ; - /** Make a node from a token - called after all else has been tried - return null for no such node */ + /** Make a node from a token - called after all else has been tried to handle special cases + * Return null for "no special node recoginzed" + */ public Node createNodeFromToken(Node scope, Token token, long line, long col) ; /** Make any node from a token as appropriate */ public Node create(Node currentGraph, Token token) ; - - public LabelToNode getLabelToNode() ; - public void setLabelToNode(LabelToNode labelToNode) ; - + public ErrorHandler getHandler() ; public void setHandler(ErrorHandler handler) ; public Prologue getPrologue() ; public void setPrologue(Prologue prologue) ; + public FactoryRDF getFactoryRDF() ; + public void setFactoryRDF(FactoryRDF factory) ; + public boolean isStrictMode() ; public void setStrictMode(boolean mode) ; } diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileBase.java b/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileBase.java index 3299c46a293..e743cdc9c02 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileBase.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileBase.java @@ -18,6 +18,8 @@ package org.apache.jena.riot.system ; +import java.util.Objects ; + import org.apache.jena.datatypes.RDFDatatype ; import org.apache.jena.datatypes.xsd.XSDDatatype ; import org.apache.jena.graph.Node ; @@ -26,7 +28,6 @@ import org.apache.jena.iri.IRI ; import org.apache.jena.riot.RiotException ; import org.apache.jena.riot.SysRIOT ; -import org.apache.jena.riot.lang.LabelToNode ; import org.apache.jena.riot.tokens.Token ; import org.apache.jena.riot.tokens.TokenType ; import org.apache.jena.sparql.core.Quad ; @@ -38,17 +39,20 @@ public class ParserProfileBase implements ParserProfile { protected ErrorHandler errorHandler ; protected Prologue prologue ; - protected LabelToNode labelMapping ; protected boolean strictMode = SysRIOT.isStrictMode() ; + protected FactoryRDF factory ; public ParserProfileBase(Prologue prologue, ErrorHandler errorHandler) { - this(prologue, errorHandler, SyntaxLabels.createLabelToNode()) ; + this(prologue, errorHandler, RiotLib.factoryRDF()) ; } - public ParserProfileBase(Prologue prologue, ErrorHandler errorHandler, LabelToNode labelMapping) { + public ParserProfileBase(Prologue prologue, ErrorHandler errorHandler, FactoryRDF factory) { + Objects.requireNonNull(prologue) ; + Objects.requireNonNull(errorHandler) ; + Objects.requireNonNull(factory) ; this.prologue = prologue ; this.errorHandler = errorHandler ; - this.labelMapping = labelMapping ; + this.factory = factory ; } @Override @@ -72,15 +76,15 @@ public void setPrologue(Prologue p) { } @Override - public LabelToNode getLabelToNode() { - return labelMapping ; + public FactoryRDF getFactoryRDF() { + return factory; } @Override - public void setLabelToNode(LabelToNode mapper) { - labelMapping = mapper ; + public void setFactoryRDF(FactoryRDF factory) { + this.factory = factory; } - + @Override public String resolveIRI(String uriStr, long line, long col) { return prologue.getResolver().resolveToString(uriStr) ; @@ -93,44 +97,44 @@ public IRI makeIRI(String uriStr, long line, long col) { @Override public Quad createQuad(Node g, Node s, Node p, Node o, long line, long col) { - return new Quad(g, s, p, o) ; + return factory.createQuad(g, s, p, o); } @Override public Triple createTriple(Node s, Node p, Node o, long line, long col) { - return new Triple(s, p, o) ; + return factory.createTriple(s, p, o); } @Override public Node createURI(String uriStr, long line, long col) { - return RiotLib.createIRIorBNode(uriStr) ; + return factory.createURI(uriStr); } @Override public Node createBlankNode(Node scope, String label, long line, long col) { - return labelMapping.get(scope, label) ; + return factory.createBlankNode(label); } @Override public Node createBlankNode(Node scope, long line, long col) { - return labelMapping.create() ; + return factory.createBlankNode(); } @Override public Node createTypedLiteral(String lexical, RDFDatatype dt, long line, long col) { - return NodeFactory.createLiteral(lexical, dt) ; + return factory.createTypedLiteral(lexical, dt); } @Override public Node createLangLiteral(String lexical, String langTag, long line, long col) { - return NodeFactory.createLiteral(lexical, langTag) ; + return factory.createLangLiteral(lexical, langTag); } @Override public Node createStringLiteral(String lexical, long line, long col) { - return NodeFactory.createLiteral(lexical) ; + return factory.createStringLiteral(lexical); } - + /** Special token forms */ @Override public Node createNodeFromToken(Node scope, Token token, long line, long col) { @@ -144,27 +148,31 @@ public Node createNodeFromToken(Node scope, Token token, long line, long col) { @Override public Node create(Node currentGraph, Token token) { - // Dispatches to the underlying operation + return create(this, currentGraph, token) ; + } + + private static Node create(ParserProfile pp, Node currentGraph, Token token) { + // Dispatches to the underlying ParserProfile operation long line = token.getLine() ; long col = token.getColumn() ; String str = token.getImage() ; switch (token.getType()) { case BNODE : - return createBlankNode(currentGraph, str, line, col) ; + return pp.createBlankNode(currentGraph, str, line, col) ; case IRI : - return createURI(str, line, col) ; + return pp.createURI(str, line, col) ; case PREFIXED_NAME : { String prefix = str ; String suffix = token.getImage2() ; - String expansion = expandPrefixedName(prefix, suffix, token) ; - return createURI(expansion, line, col) ; + String expansion = expandPrefixedName(pp, prefix, suffix, token) ; + return pp.createURI(expansion, line, col) ; } case DECIMAL : - return createTypedLiteral(str, XSDDatatype.XSDdecimal, line, col) ; + return pp.createTypedLiteral(str, XSDDatatype.XSDdecimal, line, col) ; case DOUBLE : - return createTypedLiteral(str, XSDDatatype.XSDdouble, line, col) ; + return pp.createTypedLiteral(str, XSDDatatype.XSDdouble, line, col) ; case INTEGER : - return createTypedLiteral(str, XSDDatatype.XSDinteger, line, col) ; + return pp.createTypedLiteral(str, XSDDatatype.XSDinteger, line, col) ; case LITERAL_DT : { Token tokenDT = token.getSubToken2() ; String uriStr ; @@ -176,41 +184,41 @@ public Node create(Node currentGraph, Token token) { case PREFIXED_NAME : { String prefix = tokenDT.getImage() ; String suffix = tokenDT.getImage2() ; - uriStr = expandPrefixedName(prefix, suffix, tokenDT) ; + uriStr = expandPrefixedName(pp, prefix, suffix, tokenDT) ; break ; } default : throw new RiotException("Expected IRI for datatype: " + token) ; } - uriStr = resolveIRI(uriStr, tokenDT.getLine(), tokenDT.getColumn()) ; + uriStr = pp.resolveIRI(uriStr, tokenDT.getLine(), tokenDT.getColumn()) ; RDFDatatype dt = NodeFactory.getType(uriStr) ; - return createTypedLiteral(str, dt, line, col) ; + return pp.createTypedLiteral(str, dt, line, col) ; } case LITERAL_LANG : - return createLangLiteral(str, token.getImage2(), line, col) ; + return pp.createLangLiteral(str, token.getImage2(), line, col) ; case STRING : case STRING1 : case STRING2 : case LONG_STRING1 : case LONG_STRING2 : - return createStringLiteral(str, line, col) ; + return pp.createStringLiteral(str, line, col) ; default : { - Node x = createNodeFromToken(currentGraph, token, line, col) ; + Node x = pp.createNodeFromToken(currentGraph, token, line, col) ; if (x != null) return x ; - errorHandler.fatal("Not a valid token for an RDF term: " + token, line, col) ; + pp.getHandler().fatal("Not a valid token for an RDF term: " + token, line, col) ; return null ; } } } - private String expandPrefixedName(String prefix, String localPart, Token token) { - String expansion = prologue.getPrefixMap().expand(prefix, localPart) ; + private static String expandPrefixedName(ParserProfile pp, String prefix, String localPart, Token token) { + String expansion = pp.getPrologue().getPrefixMap().expand(prefix, localPart) ; if (expansion == null) - errorHandler.fatal("Undefined prefix: " + prefix, token.getLine(), token.getColumn()) ; + pp.getHandler().fatal("Undefined prefix: " + prefix, token.getLine(), token.getColumn()) ; return expansion ; } diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileChecker.java b/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileChecker.java index 30809a6b8d4..920ce558cbe 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileChecker.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/system/ParserProfileChecker.java @@ -26,7 +26,6 @@ import org.apache.jena.riot.RiotException ; import org.apache.jena.riot.checker.CheckerIRI ; import org.apache.jena.riot.checker.CheckerLiterals ; -import org.apache.jena.riot.lang.LabelToNode ; import org.apache.jena.sparql.core.Quad ; import org.apache.jena.sparql.util.FmtUtils ; @@ -40,8 +39,7 @@ * */ -public class ParserProfileChecker extends ParserProfileBase // implements - // ParserProfile +public class ParserProfileChecker extends ParserProfileBase // implements ParserProfile { private boolean checkLiterals = true ; @@ -49,8 +47,8 @@ public ParserProfileChecker(Prologue prologue, ErrorHandler errorHandler) { super(prologue, errorHandler) ; } - public ParserProfileChecker(Prologue prologue, ErrorHandler errorHandler, LabelToNode labelMapping) { - super(prologue, errorHandler, labelMapping) ; + public ParserProfileChecker(Prologue prologue, ErrorHandler errorHandler, FactoryRDF factory) { + super(prologue, errorHandler, factory) ; } @Override @@ -105,19 +103,9 @@ private void checkQuad(Node graph, Node subject, Node predicate, Node object, lo @Override public Node createURI(String x, long line, long col) { - try { - if ( RiotLib.isBNodeIRI(x) ) - return RiotLib.createIRIorBNode(x) ; - else { - String resolvedIRI = resolveIRI(x, line, col) ; - return NodeFactory.createURI(resolvedIRI) ; - } - } - catch (RiotException ex) { - // Error was handled. - // errorHandler.error(ex.getMessage(), line, col) ; - throw ex ; - } + if ( ! RiotLib.isBNodeIRI(x) ) + x = resolveIRI(x, line, col) ; + return super.createURI(x, line, col) ; } @Override @@ -134,14 +122,14 @@ public Node createLangLiteral(String lexical, String langTag, long line, long co return n ; } - @Override - public Node createStringLiteral(String lexical, long line, long col) { - return NodeFactory.createLiteral(lexical) ; - } - - @Override - public Node createBlankNode(Node scope, String label, long line, long col) { - return labelMapping.get(scope, label) ; - } - + // No checks +// @Override +// public Node createStringLiteral(String lexical, long line, long col) { +// return super.createStringLiteral(lexical, line, col) ; +// } +// +// @Override +// public Node createBlankNode(Node scope, String label, long line, long col) { +// return super.createBlankNode(scope, label, line, col) ; +// } } diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/ProgressStreamRDF.java b/jena-arq/src/main/java/org/apache/jena/riot/system/ProgressStreamRDF.java new file mode 100644 index 00000000000..f57d41e322a --- /dev/null +++ b/jena-arq/src/main/java/org/apache/jena/riot/system/ProgressStreamRDF.java @@ -0,0 +1,65 @@ +/* + * 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.riot.system; + +import org.apache.jena.atlas.lib.ProgressMonitor ; +import org.apache.jena.graph.Triple ; +import org.apache.jena.sparql.core.Quad ; + +/** Send ticks to a {@link ProgressMonitor} as triples and quads + * are sent along the {@link StreamRDF}. + */ + +public class ProgressStreamRDF extends StreamRDFWrapper { + + private final ProgressMonitor monitor ; + + public ProgressStreamRDF(StreamRDF other, ProgressMonitor monitor) { + super(other); + this.monitor = monitor ; + } + + // Better that the app call start/finish on the monitor so that a number of + // inputs on the stream can call start/finish. i.e the monitor can be used + // for a batch of oeprations. + +// @Override +// public void start() { +// monitor.start(); +// super.start(); +// } +// +// @Override +// public void finish() { +// super.finish(); +// monitor.finish(); +// } + + @Override + public void triple(Triple triple) { + super.triple(triple); + monitor.tick(); + } + + @Override + public void quad(Quad quad) { + super.quad(quad); + monitor.tick(); + } +} diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/RiotLib.java b/jena-arq/src/main/java/org/apache/jena/riot/system/RiotLib.java index 0455295ece0..76ec07f1935 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/system/RiotLib.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/system/RiotLib.java @@ -38,10 +38,7 @@ import org.apache.jena.graph.NodeFactory ; import org.apache.jena.graph.Triple ; import org.apache.jena.query.ARQ ; -import org.apache.jena.riot.Lang ; -import org.apache.jena.riot.RDFLanguages ; -import org.apache.jena.riot.SysRIOT ; -import org.apache.jena.riot.WriterDatasetRIOT ; +import org.apache.jena.riot.* ; import org.apache.jena.riot.lang.LabelToNode ; import org.apache.jena.riot.tokens.Token ; import org.apache.jena.riot.tokens.Tokenizer ; @@ -82,7 +79,7 @@ public static boolean isBNodeIRI(String iri) return skolomizedBNodes && iri.startsWith(bNodeLabelStart) ; } - private static ParserProfile profile = profile(RDFLanguages.TURTLE, null, null) ; + private static ParserProfile profile = profile(RDFLanguages.TURTLE, null, ErrorHandlerFactory.errorHandlerStd) ; static { PrefixMap pmap = profile.getPrologue().getPrefixMap() ; pmap.add("rdf", ARQConstants.rdfPrefix) ; @@ -147,9 +144,23 @@ public static ParserProfile profile(String baseIRI, boolean resolveIRIs, boolean prologue = new Prologue(PrefixMapFactory.createForInput(), IRIResolver.createNoResolve()) ; if ( checking ) - return new ParserProfileChecker(prologue, handler, labelToNode) ; + return new ParserProfileChecker(prologue, handler, factoryRDF(labelToNode)) ; else - return new ParserProfileBase(prologue, handler, labelToNode) ; + return new ParserProfileBase(prologue, handler, factoryRDF(labelToNode)) ; + } + + /** Create a new (notinfluenced by anything else) FactoryRDF + * using the label to blank node scheme provided. + */ + public static FactoryRDF factoryRDF(LabelToNode labelMapping) { + return new FactoryRDFStd(labelMapping); + } + + /** Create a new (not influenced by anything else) FactoryRDF + * using the label to blank node scheme scope by this FactoryRDF. + */ + public static FactoryRDF factoryRDF() { + return factoryRDF(SyntaxLabels.createLabelToNode()); } /** Get triples with the same subject */ diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/SerializationFactoryFinder.java b/jena-arq/src/main/java/org/apache/jena/riot/system/SerializationFactoryFinder.java index 281defe2f93..33341225034 100644 --- a/jena-arq/src/main/java/org/apache/jena/riot/system/SerializationFactoryFinder.java +++ b/jena-arq/src/main/java/org/apache/jena/riot/system/SerializationFactoryFinder.java @@ -81,9 +81,11 @@ public Sink createSerializer(OutputStream out) @Override public Iterator createDeserializer(InputStream in) { - Tokenizer tokenizer = TokenizerFactory.makeTokenizerASCII(in) ; - ParserProfileBase profile = new ParserProfileBase(new Prologue(null, IRIResolver.createNoResolve()), null, LabelToNode.createUseLabelEncoded()) ; - LangNTriples parser = new LangNTriples(tokenizer, profile, null) ; + Tokenizer tokenizer = TokenizerFactory.makeTokenizerASCII(in); + ParserProfileBase profile = new ParserProfileBase(new Prologue(null, IRIResolver.createNoResolve()), + ErrorHandlerFactory.errorHandlerNoWarnings, + RiotLib.factoryRDF(LabelToNode.createUseLabelEncoded())); + LangNTriples parser = new LangNTriples(tokenizer, profile, null); return parser ; } @@ -110,7 +112,9 @@ public Sink createSerializer(OutputStream out) public Iterator createDeserializer(InputStream in) { Tokenizer tokenizer = TokenizerFactory.makeTokenizerASCII(in) ; - ParserProfileBase profile = new ParserProfileBase(new Prologue(null, IRIResolver.createNoResolve()), null, LabelToNode.createUseLabelEncoded()) ; + ParserProfileBase profile = new ParserProfileBase(new Prologue(null, IRIResolver.createNoResolve()), + ErrorHandlerFactory.errorHandlerNoWarnings, + RiotLib.factoryRDF(LabelToNode.createUseLabelEncoded())) ; LangNQuads parser = new LangNQuads(tokenizer, profile, null) ; return parser ; } diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/engine/binding/BindingInputStream.java b/jena-arq/src/main/java/org/apache/jena/sparql/engine/binding/BindingInputStream.java index 786f6f70316..e54c919d85a 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/engine/binding/BindingInputStream.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/engine/binding/BindingInputStream.java @@ -82,8 +82,8 @@ static ParserProfile profile() // Don't do anything with IRIs. Prologue prologue = new Prologue(PrefixMapFactory.createForInput(), IRIResolver.createNoResolve()) ; ErrorHandler handler = ErrorHandlerFactory.getDefaultErrorHandler() ; - ParserProfile profile = new ParserProfileBase(prologue, handler) ; - profile.setLabelToNode(LabelToNode.createUseLabelAsGiven()) ; + FactoryRDF factory = RiotLib.factoryRDF(LabelToNode.createUseLabelAsGiven()) ; + ParserProfile profile = new ParserProfileBase(prologue, handler, factory) ; // Include safe bNode labels. return profile ; } diff --git a/jena-arq/src/test/java/org/apache/jena/riot/system/TS_RiotSystem.java b/jena-arq/src/test/java/org/apache/jena/riot/system/TS_RiotSystem.java index 4229e78b3c2..7b4f08d53a0 100644 --- a/jena-arq/src/test/java/org/apache/jena/riot/system/TS_RiotSystem.java +++ b/jena-arq/src/test/java/org/apache/jena/riot/system/TS_RiotSystem.java @@ -30,6 +30,9 @@ @SuiteClasses({ TestChecker.class , TestStreamRDF.class + , TestFactoryRDF.class + , TestFactoryRDFCaching.class + // Prefix Map implementations , TestPrefixMap.class , TestPrefixMapWrapper.class @@ -37,11 +40,13 @@ , TestFastAbbreviatingPrefixMap.class , TestPrefixMapExtended1.class , TestPrefixMapExtended2.class + , TestIO_JenaReaders.class , TestIO_JenaWriters.class , TestLangRegistration.class , TestFormatRegistration.class , TestJsonLDReadWrite.class // Some simple testing of the jsonld-java engine. + // May be subject to performance vagaries, with the improvements made // to the fast implementation this should be fairly safe //, TestAbbreviationPerformance.class diff --git a/jena-arq/src/test/java/org/apache/jena/riot/system/TestFactoryRDF.java b/jena-arq/src/test/java/org/apache/jena/riot/system/TestFactoryRDF.java new file mode 100644 index 00000000000..75ae5f47228 --- /dev/null +++ b/jena-arq/src/test/java/org/apache/jena/riot/system/TestFactoryRDF.java @@ -0,0 +1,132 @@ +/* + * 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.riot.system; + +import static org.junit.Assert.assertEquals ; +import static org.junit.Assert.assertNotEquals ; +import static org.junit.Assert.assertNotNull ; +import static org.junit.Assert.assertTrue ; + +import org.apache.jena.datatypes.xsd.XSDDatatype ; +import org.apache.jena.graph.Graph ; +import org.apache.jena.graph.Node ; +import org.apache.jena.graph.Triple ; +import org.apache.jena.riot.lang.LabelToNode ; +import org.apache.jena.riot.system.FactoryRDF ; +import org.apache.jena.riot.system.FactoryRDFStd ; +import org.apache.jena.sparql.core.DatasetGraph ; +import org.apache.jena.sparql.core.Quad ; +import org.apache.jena.vocabulary.RDF ; +import org.junit.Test ; + +public class TestFactoryRDF { + protected FactoryRDF factory = new FactoryRDFStd(LabelToNode.createUseLabelAsGiven()) ; + + @Test public void factoryRDF_blanknode_01() { + Node n1 = factory.createBlankNode() ; + assertTrue(n1.isBlank()) ; + Node n2 = factory.createBlankNode() ; + assertNotEquals(n1, n2); + } + + @Test public void factoryRDF_blanknode_02() { + Node n1 = factory.createBlankNode("ABCDE") ; + assertTrue(n1.isBlank()) ; + Node n2 = factory.createBlankNode("ABCDE") ; + assertEquals(n1, n2); + assertEquals("ABCDE", n1.getBlankNodeLabel()) ; + } + + @Test public void factoryRDF_blanknode_03() { + Node n1 = factory.createBlankNode(0x1234L, 0x5678L) ; + assertTrue(n1.isBlank()) ; + Node n2 = factory.createBlankNode(0x1234L, 0x5678L) ; + assertEquals(n1, n2); + assertEquals("0000123400005678", n1.getBlankNodeLabel()) ; + } + + @Test public void factoryRDF_uri_02() { + Node n = factory.createURI("http://example/") ; + assertTrue(n.isURI()) ; + assertEquals("http://example/", n.getURI()) ; + } + + @Test public void factoryRDF_uri_03() { + Node n = factory.createURI("_:abc") ; // Blank node! + assertTrue(n.isBlank()) ; + assertEquals("abc", n.getBlankNodeLabel()) ; + } + + @Test public void factoryRDF_literal_01() { + Node n = factory.createStringLiteral("hello") ; + assertTrue(n.isLiteral()) ; + assertEquals("hello", n.getLiteralLexicalForm()) ; + assertEquals(XSDDatatype.XSDstring, n.getLiteralDatatype()) ; + assertEquals("", n.getLiteralLanguage()) ; + } + + @Test public void factoryRDF_literal_02() { + Node n = factory.createLangLiteral("xyz", "en") ; + assertTrue(n.isLiteral()) ; + assertEquals("xyz", n.getLiteralLexicalForm()) ; + assertEquals(RDF.dtLangString, n.getLiteralDatatype()) ; + assertEquals("en", n.getLiteralLanguage()) ; + } + + @Test public void factoryRDF_literal_03() { + Node n = factory.createTypedLiteral("1", XSDDatatype.XSDinteger) ; + assertTrue(n.isLiteral()) ; + assertEquals("1", n.getLiteralLexicalForm()) ; + assertEquals(XSDDatatype.XSDinteger, n.getLiteralDatatype()) ; + assertEquals("", n.getLiteralLanguage()) ; + } + + @Test public void factoryRDF_triple_01() { + Node s = factory.createURI("http://test/s") ; + Node p = factory.createURI("http://test/p") ; + Node o = factory.createURI("http://test/o") ; + Triple triple = factory.createTriple(s, p, o) ; + assertEquals(s, triple.getSubject()) ; + assertEquals(p, triple.getPredicate()) ; + assertEquals(o, triple.getObject()) ; + } + + @Test public void factoryRDF_quad_01() { + Node g = factory.createURI("http://test/g") ; + Node s = factory.createURI("http://test/s") ; + Node p = factory.createURI("http://test/p") ; + Node o = factory.createURI("http://test/o") ; + Quad quad = factory.createQuad(g, s, p, o) ; + assertEquals(g, quad.getGraph()) ; + assertEquals(s, quad.getSubject()) ; + assertEquals(p, quad.getPredicate()) ; + assertEquals(o, quad.getObject()) ; + } + + @Test public void factoryRDF_graph_01() { + Graph graph = factory.createGraph() ; + assertNotNull(graph) ; + } + + @Test public void factoryRDF_dataset_01() { + DatasetGraph dsg = factory.createDatasetGraph() ; + assertNotNull(dsg) ; + } +} + diff --git a/jena-arq/src/test/java/org/apache/jena/riot/system/TestFactoryRDFCaching.java b/jena-arq/src/test/java/org/apache/jena/riot/system/TestFactoryRDFCaching.java new file mode 100644 index 00000000000..b51c3913550 --- /dev/null +++ b/jena-arq/src/test/java/org/apache/jena/riot/system/TestFactoryRDFCaching.java @@ -0,0 +1,47 @@ +/* + * 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.riot.system; + +import static org.junit.Assert. * ; +import org.apache.jena.graph.Node ; +import org.apache.jena.riot.lang.LabelToNode ; +import org.apache.jena.riot.system.FactoryRDFCaching ; +import org.junit.Test ; + +public class TestFactoryRDFCaching extends TestFactoryRDF { + + public TestFactoryRDFCaching() { + super.factory = new FactoryRDFCaching(100, LabelToNode.createUseLabelAsGiven()) ; + } + + @Test public void factory_cache_01() { + Node n1 = factory.createStringLiteral("") ; + Node n2 = factory.createStringLiteral("") ; + assertSame(n1, n2); + } + + @Test public void factory_cache_02() { + Node n1 = factory.createURI("http://test/n1") ; + Node n2 = factory.createURI("http://test/n2") ; + Node n3 = factory.createURI("http://test/n1") ; + assertSame(n1, n3); + } +} + + diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheInfo.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheInfo.java index 11fafc544fa..9a4fae1c4c9 100644 --- a/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheInfo.java +++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/cache/CacheInfo.java @@ -21,42 +21,28 @@ import org.apache.jena.ext.com.google.common.cache.CacheStats ; /** Simplified version of Guava's CacheStats (and abstractign away from Guava cache implementation) */ - public class CacheInfo { - public final long requests; - public final long hits; - public final long misses; - public final double hitRate; - public final int cacheSize; +public class CacheInfo { + public final long requests; + public final long hits; + public final long misses; + public final double hitRate; + public final int cacheSize; - public CacheInfo(int cacheSize, CacheStats stats) { - this(cacheSize, stats.requestCount(), stats.hitCount(), stats.missCount(), stats.hitRate() ) ; - } - - public CacheInfo(int cacheSize, long requests, long hits, long misses, double hitRate) { - this.cacheSize = cacheSize ; - this.requests = requests ; - this.hits = hits ; - this.misses = misses ; - this.hitRate = hitRate ; - } + public CacheInfo(int cacheSize, CacheStats stats) { + this(cacheSize, stats.requestCount(), stats.hitCount(), stats.missCount(), stats.hitRate() ) ; + } - @Override - public String toString() { - return String.format("size=%,d count=%,d hits=%,d misses=%,d rate=%.1f", - cacheSize, requests, hits, misses, hitRate) ; - } - -// private void details(String label, CacheGuava cache, int cacheSize) { -// System.out.printf("%s [%,d]\n", label, cacheSize) ; -// CacheStats stats = ((CacheGuava)cache).stats() ; -//// System.out.printf(" Cache usage: %,d\n", cache.size()) ; -// System.out.printf(" Requests: %,d\n", stats.requestCount()) ; -// System.out.printf(" Hit rate: %.1f%%\n", 100*stats.hitRate()) ; -//// System.out.printf(" Hits: %,d\n", stats.hitCount()) ; -//// System.out.printf(" Misses: %,d\n", stats.missCount()) ; -//// if ( stats.loadSuccessCount() != stats.missCount() ) { -//// System.out.printf(" Load success: %,d\n", stats.loadSuccessCount()) ; -//// System.out.printf(" Load ex: %,d\n", stats.loadExceptionCount()) ; -//// } + public CacheInfo(int cacheSize, long requests, long hits, long misses, double hitRate) { + this.cacheSize = cacheSize ; + this.requests = requests ; + this.hits = hits ; + this.misses = misses ; + this.hitRate = hitRate ; + } - } \ No newline at end of file + @Override + public String toString() { + return String.format("size=%,d count=%,d hits=%,d misses=%,d rate=%.1f", + cacheSize, requests, hits, misses, hitRate) ; + } +} \ No newline at end of file diff --git a/jena-cmds/src/main/java/riotcmd/CmdLangParse.java b/jena-cmds/src/main/java/riotcmd/CmdLangParse.java index 61f3b968205..080edd79664 100644 --- a/jena-cmds/src/main/java/riotcmd/CmdLangParse.java +++ b/jena-cmds/src/main/java/riotcmd/CmdLangParse.java @@ -276,8 +276,11 @@ else if ( RDFLanguages.isTriples(lang) ) } else reader.setParserProfile(RiotLib.profile(baseURI, false, false, errHandler)) ; - if ( labelsAsGiven ) - reader.getParserProfile().setLabelToNode(LabelToNode.createUseLabelAsGiven()) ; + if ( labelsAsGiven ) { + FactoryRDF f = RiotLib.factoryRDF(LabelToNode.createUseLabelAsGiven()) ; + reader.getParserProfile().setFactoryRDF(f); + } + modTime.startTimer() ; sink.start() ; reader.read(in, baseURI, ct, sink, null) ; diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java index b05fc4ebeb6..0da573f3732 100644 --- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java +++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java @@ -19,21 +19,9 @@ import java.util.HashMap; import java.util.Map; -import java.util.Stack; - -import org.apache.jena.arq.querybuilder.clauses.ConstructClause; -import org.apache.jena.arq.querybuilder.clauses.DatasetClause; import org.apache.jena.arq.querybuilder.clauses.PrologClause; -import org.apache.jena.arq.querybuilder.clauses.SelectClause; -import org.apache.jena.arq.querybuilder.clauses.SolutionModifierClause; -import org.apache.jena.arq.querybuilder.clauses.WhereClause; -import org.apache.jena.arq.querybuilder.handlers.ConstructHandler; -import org.apache.jena.arq.querybuilder.handlers.DatasetHandler; -import org.apache.jena.arq.querybuilder.handlers.Handler; +import org.apache.jena.arq.querybuilder.handlers.HandlerBlock; import org.apache.jena.arq.querybuilder.handlers.PrologHandler; -import org.apache.jena.arq.querybuilder.handlers.SelectHandler; -import org.apache.jena.arq.querybuilder.handlers.SolutionModifierHandler; -import org.apache.jena.arq.querybuilder.handlers.WhereHandler; import org.apache.jena.graph.FrontsNode ; import org.apache.jena.graph.Node ; import org.apache.jena.graph.NodeFactory ; @@ -58,8 +46,6 @@ public abstract class AbstractQueryBuilder> implements Cloneable, PrologClause { - // all queries have prologs - protected PrologHandler prologHandler; // the query this builder is building protected Query query; // a map of vars to nodes for replacement during build. @@ -175,9 +161,20 @@ public Var makeVar(Object o) throws ARQInternalErrorException { */ protected AbstractQueryBuilder() { query = new Query(); - prologHandler = new PrologHandler(query); values = new HashMap(); } + + /** + * Get the HandlerBlock for this query builder. + * @return The associated handler block. + */ + public abstract HandlerBlock getHandlerBlock(); + + @Override + public final PrologHandler getPrologHandler() { + return getHandlerBlock().getPrologHandler(); + } + /** * Set a variable replacement. During build all instances of var in the @@ -220,11 +217,6 @@ public void setVar(Object var, Object value) { } } - @Override - public PrologHandler getPrologHandler() { - return prologHandler; - } - @Override public T addPrefix(String pfx, Resource uri) { return addPrefix(pfx, uri.getURI()); @@ -238,21 +230,21 @@ public T addPrefix(String pfx, Node uri) { @SuppressWarnings("unchecked") @Override public T addPrefix(String pfx, String uri) { - prologHandler.addPrefix(pfx, uri); + getPrologHandler().addPrefix(pfx, uri); return (T) this; } @SuppressWarnings("unchecked") @Override public T addPrefixes(Map prefixes) { - prologHandler.addPrefixes(prefixes); + getPrologHandler().addPrefixes(prefixes); return (T) this; } @SuppressWarnings("unchecked") @Override public T setBase(String base) { - prologHandler.setBase(base); + getPrologHandler().setBase(base); return (T) this; } @@ -285,6 +277,8 @@ public final String buildString() { */ public final Query build() { Query q = new Query(); + + // set the query type switch (query.getQueryType()) { case Query.QueryTypeAsk: @@ -303,51 +297,20 @@ public final Query build() { throw new IllegalStateException( "Internal query is not a known type: "+q.getQueryType()); } - Stack handlerStack = new Stack(); - PrologHandler ph = new PrologHandler(q); - handlerStack.push(ph); - ph.addAll(prologHandler); - ph.setVars(values); - if (this instanceof SelectClause) { - SelectHandler sh = new SelectHandler(q); - sh.addAll(((SelectClause) this).getSelectHandler()); - sh.setVars(values); - handlerStack.push(sh); - } - if (this instanceof ConstructClause) { - ConstructHandler ch = new ConstructHandler(q); - ch.addAll(((ConstructClause) this).getConstructHandler()); - ch.setVars(values); - handlerStack.push(ch); - } - if (this instanceof DatasetClause) { - DatasetHandler dh = new DatasetHandler(q); - dh.addAll(((DatasetClause) this).getDatasetHandler()); - dh.setVars(values); - handlerStack.push(dh); - } - if (this instanceof SolutionModifierClause) { - SolutionModifierHandler smh = new SolutionModifierHandler(q); - smh.addAll(((SolutionModifierClause) this) - .getSolutionModifierHandler()); - smh.setVars(values); - handlerStack.push(smh); - } - if (this instanceof WhereClause) { - WhereHandler wh = new WhereHandler(q); - wh.addAll(((WhereClause) this).getWhereHandler()); - wh.setVars(values); - handlerStack.push(wh); - } - + // use the HandlerBlock implementation to copy the data. + HandlerBlock handlerBlock = new HandlerBlock(q); + handlerBlock.addAll( getHandlerBlock() ); + + // set the vars + handlerBlock.setVars(values); + // make sure we have a query pattern before we start building. if (q.getQueryPattern() == null) { q.setQueryPattern( new ElementGroup() ); } - while (!handlerStack.isEmpty()) { - handlerStack.pop().build(); - } + + handlerBlock.build(); return q; } @@ -365,6 +328,7 @@ public final Query build() { public static Query clone(Query q2) { Query retval = new Query(); + // set the query type if (q2.isSelectType()) { retval.setQuerySelectType(); @@ -378,13 +342,11 @@ public static Query clone(Query q2) { retval.setQueryConstructType(); } - new PrologHandler(retval).addAll(new PrologHandler(q2)); - new ConstructHandler(retval).addAll(new ConstructHandler(q2)); - new DatasetHandler(retval).addAll(new DatasetHandler(q2)); - new SolutionModifierHandler(retval).addAll(new SolutionModifierHandler( - q2)); - new WhereHandler(retval).addAll(new WhereHandler(q2)); - new SelectHandler(retval).addAll(new SelectHandler(q2)); + // use the handler block to clone the data + HandlerBlock hb = new HandlerBlock( retval ); + HandlerBlock hb2 = new HandlerBlock( q2 ); + hb.addAll(hb2); + return retval; } @@ -398,12 +360,8 @@ public static Query clone(Query q2) { * @return The new query with the specified vars replaced. */ public static Query rewrite(Query q2, Map values) { - new PrologHandler(q2).setVars(values); - new ConstructHandler(q2).setVars(values); - new DatasetHandler(q2).setVars(values); - new SolutionModifierHandler(q2).setVars(values); - new WhereHandler(q2).setVars(values); - new SelectHandler(q2).setVars(values); + HandlerBlock hb = new HandlerBlock(q2); + hb.setVars(values); return q2; } } diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AskBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AskBuilder.java index 1e2c437ac75..9ae7fa22ae4 100644 --- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AskBuilder.java +++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AskBuilder.java @@ -23,6 +23,7 @@ import org.apache.jena.arq.querybuilder.clauses.SolutionModifierClause; import org.apache.jena.arq.querybuilder.clauses.WhereClause; import org.apache.jena.arq.querybuilder.handlers.DatasetHandler; +import org.apache.jena.arq.querybuilder.handlers.HandlerBlock; import org.apache.jena.arq.querybuilder.handlers.SolutionModifierHandler; import org.apache.jena.arq.querybuilder.handlers.WhereHandler; import org.apache.jena.graph.FrontsTriple ; @@ -38,12 +39,8 @@ public class AskBuilder extends AbstractQueryBuilder implements DatasetClause, WhereClause, SolutionModifierClause { - // the dataset handler - private final DatasetHandler datasetHandler; - // the where handler. - private final WhereHandler whereHandler; - // the solution modifier handler. - private final SolutionModifierHandler solutionModifier; + + private final HandlerBlock handlerBlock; /** * The constructor @@ -51,63 +48,65 @@ public class AskBuilder extends AbstractQueryBuilder implements public AskBuilder() { super(); query.setQueryAskType(); - datasetHandler = new DatasetHandler(query); - whereHandler = new WhereHandler(query); - solutionModifier = new SolutionModifierHandler(query); + handlerBlock = new HandlerBlock( query ); } - + + @Override + public HandlerBlock getHandlerBlock() + { + return handlerBlock; + } + @Override public DatasetHandler getDatasetHandler() { - return datasetHandler; + return handlerBlock.getDatasetHandler(); } @Override public WhereHandler getWhereHandler() { - return whereHandler; + return handlerBlock.getWhereHandler(); } @Override public AskBuilder clone() { AskBuilder qb = new AskBuilder(); - qb.prologHandler.addAll(prologHandler); - qb.datasetHandler.addAll(datasetHandler); - qb.solutionModifier.addAll(solutionModifier); + qb.handlerBlock.addAll( handlerBlock ); return qb; } @Override public AskBuilder fromNamed(String graphName) { - datasetHandler.fromNamed(graphName); + getDatasetHandler().fromNamed(graphName); return this; } @Override public AskBuilder fromNamed(Collection graphNames) { - datasetHandler.fromNamed(graphNames); + getDatasetHandler().fromNamed(graphNames); return this; } @Override public AskBuilder from(String graphName) { - datasetHandler.from(graphName); + getDatasetHandler().from(graphName); return this; } @Override public AskBuilder from(Collection graphName) { - datasetHandler.from(graphName); + getDatasetHandler().from(graphName); return this; } @Override public AskBuilder addWhere(Triple t) { - whereHandler.addWhere(t); + getWhereHandler().addWhere(t); return this; } @Override public AskBuilder addWhere(FrontsTriple t) { - whereHandler.addWhere(t.asTriple()); + getWhereHandler().addWhere(t.asTriple()); return this; } @@ -119,20 +118,20 @@ public AskBuilder addWhere(Object s, Object p, Object o) { @Override public AskBuilder addOptional(Triple t) { - whereHandler.addOptional(t); + getWhereHandler().addOptional(t); return this; } @Override public AskBuilder addOptional(SelectBuilder t) { - whereHandler.addOptional(t.getWhereHandler()); + getWhereHandler().addOptional(t.getWhereHandler()); return this; } @Override public AskBuilder addOptional(FrontsTriple t) { - whereHandler.addOptional(t.asTriple()); + getWhereHandler().addOptional(t.asTriple()); return this; } @@ -144,78 +143,77 @@ public AskBuilder addOptional(Object s, Object p, Object o) { @Override public AskBuilder addFilter(String s) throws ParseException { - whereHandler.addFilter(s); + getWhereHandler().addFilter(s); return this; } @Override public AskBuilder addSubQuery(SelectBuilder subQuery) { - prologHandler.addAll(subQuery.getPrologHandler()); - whereHandler.addSubQuery(subQuery); + getWhereHandler().addSubQuery(subQuery); return this; } @Override public AskBuilder addUnion(SelectBuilder subQuery) { - whereHandler.addUnion(subQuery); + getWhereHandler().addUnion(subQuery); return this; } @Override public AskBuilder addGraph(Object graph, SelectBuilder subQuery) { - prologHandler.addAll(subQuery.getPrologHandler()); - whereHandler.addGraph(makeNode(graph), subQuery.getWhereHandler()); + getPrologHandler().addAll(subQuery.getPrologHandler()); + getWhereHandler().addGraph(makeNode(graph), subQuery.getWhereHandler()); return this; } @Override public AskBuilder addBind(Expr expression, Object var) { - whereHandler.addBind( expression, makeVar(var) ); + getWhereHandler().addBind( expression, makeVar(var) ); return this; } @Override public AskBuilder addBind(String expression, Object var) throws ParseException { - whereHandler.addBind( expression, makeVar(var) ); + getWhereHandler().addBind( expression, makeVar(var) ); return this; } @Override public AskBuilder addOrderBy(String orderBy) { - solutionModifier.addOrderBy(orderBy); + getSolutionModifierHandler().addOrderBy(orderBy); return this; } @Override public AskBuilder addGroupBy(String groupBy) { - solutionModifier.addGroupBy(groupBy); + getSolutionModifierHandler().addGroupBy(groupBy); return this; } @Override public AskBuilder addHaving(String having) throws ParseException { - solutionModifier.addHaving(having); + getSolutionModifierHandler().addHaving(having); return this; } @Override public AskBuilder setLimit(int limit) { - solutionModifier.setLimit(limit); + getSolutionModifierHandler().setLimit(limit); return this; } @Override public AskBuilder setOffset(int offset) { - solutionModifier.setOffset(offset); + getSolutionModifierHandler().setOffset(offset); return this; } @Override public SolutionModifierHandler getSolutionModifierHandler() { - return solutionModifier; + return handlerBlock.getModifierHandler(); } @Override public Node list(Object... objs) { - return whereHandler.list(objs); + return getWhereHandler().list(objs); } } \ No newline at end of file diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/ConstructBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/ConstructBuilder.java index 034fdefcd97..64324a4623c 100644 --- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/ConstructBuilder.java +++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/ConstructBuilder.java @@ -25,6 +25,7 @@ import org.apache.jena.arq.querybuilder.clauses.WhereClause; import org.apache.jena.arq.querybuilder.handlers.ConstructHandler; import org.apache.jena.arq.querybuilder.handlers.DatasetHandler; +import org.apache.jena.arq.querybuilder.handlers.HandlerBlock; import org.apache.jena.arq.querybuilder.handlers.SolutionModifierHandler; import org.apache.jena.arq.querybuilder.handlers.WhereHandler; import org.apache.jena.graph.FrontsTriple ; @@ -43,118 +44,113 @@ public class ConstructBuilder extends AbstractQueryBuilder SolutionModifierClause, ConstructClause { - // the handlers used by this builder - private final DatasetHandler datasetHandler; - private final WhereHandler whereHandler; - private final SolutionModifierHandler solutionModifier; - private final ConstructHandler constructHandler; - + private final HandlerBlock handlerBlock; + /** * Constructor */ public ConstructBuilder() { super(); query.setQueryConstructType(); - datasetHandler = new DatasetHandler(query); - whereHandler = new WhereHandler(query); - solutionModifier = new SolutionModifierHandler(query); - constructHandler = new ConstructHandler(query); + handlerBlock = new HandlerBlock(query); } @Override public DatasetHandler getDatasetHandler() { - return datasetHandler; + return handlerBlock.getDatasetHandler(); } @Override public WhereHandler getWhereHandler() { - return whereHandler; + return handlerBlock.getWhereHandler(); } @Override public ConstructHandler getConstructHandler() { - return constructHandler; + return handlerBlock.getConstructHandler(); } @Override public SolutionModifierHandler getSolutionModifierHandler() { - return solutionModifier; + return handlerBlock.getModifierHandler(); } + @Override + public HandlerBlock getHandlerBlock() + { + return handlerBlock; + } + @Override public ConstructBuilder clone() { ConstructBuilder qb = new ConstructBuilder(); - qb.prologHandler.addAll(prologHandler); - qb.datasetHandler.addAll(datasetHandler); - qb.whereHandler.addAll(whereHandler); - qb.solutionModifier.addAll(solutionModifier); - qb.constructHandler.addAll(constructHandler); + qb.handlerBlock.addAll( handlerBlock ); return qb; } @Override public ConstructBuilder fromNamed(String graphName) { - datasetHandler.fromNamed(graphName); + getDatasetHandler().fromNamed(graphName); return this; } @Override public ConstructBuilder fromNamed(Collection graphNames) { - datasetHandler.fromNamed(graphNames); + getDatasetHandler().fromNamed(graphNames); return this; } @Override public ConstructBuilder from(String graphName) { - datasetHandler.from(graphName); + getDatasetHandler().from(graphName); return this; } @Override public ConstructBuilder from(Collection graphName) { - datasetHandler.from(graphName); + getDatasetHandler().from(graphName); return this; } @Override public ConstructBuilder addOrderBy(String orderBy) { - solutionModifier.addOrderBy(orderBy); + getSolutionModifierHandler().addOrderBy(orderBy); return this; } @Override public ConstructBuilder addGroupBy(String groupBy) { - solutionModifier.addGroupBy(groupBy); + getSolutionModifierHandler().addGroupBy(groupBy); return this; } @Override public ConstructBuilder addHaving(String having) throws ParseException { - solutionModifier.addHaving(having); + getSolutionModifierHandler().addHaving(having); return this; } @Override public ConstructBuilder setLimit(int limit) { - solutionModifier.setLimit(limit); + getSolutionModifierHandler().setLimit(limit); return this; } @Override public ConstructBuilder setOffset(int offset) { - solutionModifier.setOffset(offset); + getSolutionModifierHandler().setOffset(offset); return this; } @Override public ConstructBuilder addWhere(Triple t) { - whereHandler.addWhere(t); + getWhereHandler().addWhere(t); return this; } @Override public ConstructBuilder addWhere(FrontsTriple t) { - whereHandler.addWhere(t.asTriple()); + getWhereHandler().addWhere(t.asTriple()); return this; } @@ -166,20 +162,20 @@ public ConstructBuilder addWhere(Object s, Object p, Object o) { @Override public ConstructBuilder addOptional(Triple t) { - whereHandler.addOptional(t); + getWhereHandler().addOptional(t); return this; } @Override public ConstructBuilder addOptional(SelectBuilder t) { - whereHandler.addOptional(t.getWhereHandler()); + getWhereHandler().addOptional(t.getWhereHandler()); return this; } @Override public ConstructBuilder addOptional(FrontsTriple t) { - whereHandler.addOptional(t.asTriple()); + getWhereHandler().addOptional(t.asTriple()); return this; } @@ -191,45 +187,44 @@ public ConstructBuilder addOptional(Object s, Object p, Object o) { @Override public ConstructBuilder addFilter(String s) throws ParseException { - whereHandler.addFilter(s); + getWhereHandler().addFilter(s); return this; } @Override public ConstructBuilder addSubQuery(SelectBuilder subQuery) { - prologHandler.addAll(subQuery.prologHandler); - whereHandler.addSubQuery(subQuery); + getWhereHandler().addSubQuery(subQuery); return this; } @Override public ConstructBuilder addUnion(SelectBuilder subQuery) { - whereHandler.addUnion(subQuery); + getWhereHandler().addUnion(subQuery); return this; } @Override public ConstructBuilder addGraph(Object graph, SelectBuilder subQuery) { - prologHandler.addAll(subQuery.prologHandler); - whereHandler.addGraph(makeNode(graph), subQuery.getWhereHandler()); + getPrologHandler().addAll(subQuery.getPrologHandler()); + getWhereHandler().addGraph(makeNode(graph), subQuery.getWhereHandler()); return this; } @Override public ConstructBuilder addBind(Expr expression, Object var) { - whereHandler.addBind( expression, makeVar(var) ); + getWhereHandler().addBind( expression, makeVar(var) ); return this; } @Override public ConstructBuilder addBind(String expression, Object var) throws ParseException { - whereHandler.addBind( expression, makeVar(var) ); + getWhereHandler().addBind( expression, makeVar(var) ); return this; } @Override public ConstructBuilder addConstruct(Triple t) { - constructHandler.addConstruct(t); + getConstructHandler().addConstruct(t); return this; } @@ -245,6 +240,6 @@ public ConstructBuilder addConstruct(Object s, Object p, Object o) { @Override public Node list(Object... objs) { - return whereHandler.list(objs); + return getWhereHandler().list(objs); } } \ No newline at end of file diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/SelectBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/SelectBuilder.java index 12a909eefd1..03796e93664 100644 --- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/SelectBuilder.java +++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/SelectBuilder.java @@ -25,6 +25,7 @@ import org.apache.jena.arq.querybuilder.clauses.SolutionModifierClause; import org.apache.jena.arq.querybuilder.clauses.WhereClause; import org.apache.jena.arq.querybuilder.handlers.DatasetHandler; +import org.apache.jena.arq.querybuilder.handlers.HandlerBlock; import org.apache.jena.arq.querybuilder.handlers.SelectHandler; import org.apache.jena.arq.querybuilder.handlers.SolutionModifierHandler; import org.apache.jena.arq.querybuilder.handlers.WhereHandler; @@ -44,61 +45,55 @@ public class SelectBuilder extends AbstractQueryBuilder implements DatasetClause, WhereClause, SolutionModifierClause, SelectClause { - // the handlers. - private DatasetHandler datasetHandler; - private WhereHandler whereHandler; - private SolutionModifierHandler solutionModifier; - private SelectHandler selectHandler; - + private final HandlerBlock handlerBlock; + /** * Constructor. */ public SelectBuilder() { super(); query.setQuerySelectType(); - datasetHandler = new DatasetHandler(query); - whereHandler = new WhereHandler(query); - solutionModifier = new SolutionModifierHandler(query); - selectHandler = new SelectHandler(query); + handlerBlock = new HandlerBlock( query ); } @Override public DatasetHandler getDatasetHandler() { - return datasetHandler; + return handlerBlock.getDatasetHandler(); } + @Override + public HandlerBlock getHandlerBlock() + { + return handlerBlock; + } + @Override public WhereHandler getWhereHandler() { - return whereHandler; + return handlerBlock.getWhereHandler(); } @Override public SelectBuilder clone() { SelectBuilder qb = new SelectBuilder(); - qb.prologHandler.addAll(prologHandler); - qb.datasetHandler.addAll(datasetHandler); - qb.whereHandler.addAll(whereHandler); - qb.solutionModifier.addAll(solutionModifier); - qb.selectHandler.addAll(selectHandler); - + qb.handlerBlock.addAll(handlerBlock); return qb; } @Override public SelectBuilder setDistinct(boolean state) { - selectHandler.setDistinct(state); + getSelectHandler().setDistinct(state); return this; } @Override public SelectBuilder setReduced(boolean state) { - selectHandler.setReduced(state); + getSelectHandler().setReduced(state); return this; } @Override public SelectBuilder addVar(Object var) { - selectHandler.addVar(makeVar(var)); + getSelectHandler().addVar(makeVar(var)); return this; } @@ -109,77 +104,77 @@ public SelectBuilder addVar(Object var) { */ @Override public SelectBuilder addVar(String expression, Object var) throws ParseException { - selectHandler.addVar( expression, makeVar(var) ); + getSelectHandler().addVar( expression, makeVar(var) ); return this; } @Override public SelectBuilder addVar(Expr expr, Object var) { - selectHandler.addVar(expr, makeVar(var)); + getSelectHandler().addVar(expr, makeVar(var)); return this; } @Override public List getVars() { - return selectHandler.getVars(); + return getSelectHandler().getVars(); } @Override public SelectBuilder fromNamed(String graphName) { - datasetHandler.fromNamed(graphName); + getDatasetHandler().fromNamed(graphName); return this; } @Override public SelectBuilder fromNamed(Collection graphNames) { - datasetHandler.fromNamed(graphNames); + getDatasetHandler().fromNamed(graphNames); return this; } @Override public SelectBuilder from(String graphName) { - datasetHandler.from(graphName); + getDatasetHandler().from(graphName); return this; } @Override public SelectBuilder from(Collection graphName) { - datasetHandler.from(graphName); + getDatasetHandler().from(graphName); return this; } @Override public SelectBuilder addOrderBy(String orderBy) { - solutionModifier.addOrderBy(orderBy); + getSolutionModifierHandler().addOrderBy(orderBy); return this; } @Override public SelectBuilder addGroupBy(String groupBy) { - solutionModifier.addGroupBy(groupBy); + getSolutionModifierHandler().addGroupBy(groupBy); return this; } @Override public SolutionModifierHandler getSolutionModifierHandler() { - return solutionModifier; + return handlerBlock.getModifierHandler(); } @Override public SelectBuilder addHaving(String having) throws ParseException { - solutionModifier.addHaving(having); + getSolutionModifierHandler().addHaving(having); return this; } @Override public SelectBuilder setLimit(int limit) { - solutionModifier.setLimit(limit); + getSolutionModifierHandler().setLimit(limit); return this; } @Override public SelectBuilder setOffset(int offset) { - solutionModifier.setOffset(offset); + getSolutionModifierHandler().setOffset(offset); return this; } @@ -231,13 +226,13 @@ public static String makeString(Object o) { @Override public SelectBuilder addWhere(Triple t) { - whereHandler.addWhere(t); + getWhereHandler().addWhere(t); return this; } @Override public SelectBuilder addWhere(FrontsTriple t) { - whereHandler.addWhere(t.asTriple()); + getWhereHandler().addWhere(t.asTriple()); return this; } @@ -249,13 +244,13 @@ public SelectBuilder addWhere(Object s, Object p, Object o) { @Override public SelectBuilder addOptional(Triple t) { - whereHandler.addOptional(t); + getWhereHandler().addOptional(t); return this; } @Override public SelectBuilder addOptional(FrontsTriple t) { - whereHandler.addOptional(t.asTriple()); + getWhereHandler().addOptional(t.asTriple()); return this; } @@ -268,55 +263,54 @@ public SelectBuilder addOptional(Object s, Object p, Object o) { @Override public SelectBuilder addOptional(SelectBuilder t) { - whereHandler.addOptional(t.getWhereHandler()); + getWhereHandler().addOptional(t.getWhereHandler()); return this; } @Override public SelectBuilder addFilter(String s) throws ParseException { - whereHandler.addFilter(s); + getWhereHandler().addFilter(s); return this; } @Override public SelectBuilder addSubQuery(SelectBuilder subQuery) { - prologHandler.addAll(subQuery.prologHandler); - whereHandler.addSubQuery(subQuery); + getWhereHandler().addSubQuery(subQuery); return this; } @Override public SelectBuilder addUnion(SelectBuilder subQuery) { - whereHandler.addUnion(subQuery); + getWhereHandler().addUnion(subQuery); return this; } @Override public SelectBuilder addGraph(Object graph, SelectBuilder subQuery) { - prologHandler.addAll(subQuery.prologHandler); - whereHandler.addGraph(makeNode(graph), subQuery.whereHandler); + getPrologHandler().addAll(subQuery.getPrologHandler()); + getWhereHandler().addGraph(makeNode(graph), subQuery.getWhereHandler()); return this; } @Override public SelectBuilder addBind(Expr expression, Object var) { - whereHandler.addBind( expression, makeVar(var) ); + getWhereHandler().addBind( expression, makeVar(var) ); return this; } @Override public SelectBuilder addBind(String expression, Object var) throws ParseException { - whereHandler.addBind( expression, makeVar(var) ); + getWhereHandler().addBind( expression, makeVar(var) ); return this; } @Override public SelectHandler getSelectHandler() { - return selectHandler; + return handlerBlock.getSelectHandler(); } @Override public Node list(Object... objs) { - return whereHandler.list(objs); + return getWhereHandler().list(objs); } } \ No newline at end of file diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/SelectClause.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/SelectClause.java index 261db7bdc42..dc83218b2b6 100644 --- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/SelectClause.java +++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/clauses/SelectClause.java @@ -22,7 +22,6 @@ import org.apache.jena.arq.querybuilder.AbstractQueryBuilder; import org.apache.jena.arq.querybuilder.handlers.SelectHandler; import org.apache.jena.sparql.core.Var; -import org.apache.jena.sparql.core.VarExprList; import org.apache.jena.sparql.expr.Expr; import org.apache.jena.sparql.lang.sparql_11.ParseException; diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/AggregationHandler.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/AggregationHandler.java new file mode 100644 index 00000000000..f999ca8237d --- /dev/null +++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/AggregationHandler.java @@ -0,0 +1,110 @@ +package org.apache.jena.arq.querybuilder.handlers; +/* + * 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. + */ +import java.util.HashMap; +import java.util.Map; + +import org.apache.jena.graph.Node; +import org.apache.jena.query.Query; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.expr.Expr; +import org.apache.jena.sparql.expr.ExprAggregator; + +/** + * Class to handle manipulation the aggregation variables in the query. + * + */ +public class AggregationHandler implements Handler { + // the query + private final Query query; + + // a map of variables to aggregators + private final Map aggMap; + + /** + * Constructor. + * @param query the query to handle. + */ + public AggregationHandler( Query query ) + { + this.query = query; + aggMap = new HashMap(); + } + + /** + * Add all the aggregations from the other handler. + * @param handler The other handler. + * @return This handler for chaining. + */ + public AggregationHandler addAll(AggregationHandler handler) + { + for (ExprAggregator agg : handler.query.getAggregators()) + { + query.allocAggregate(agg.getAggregator()); + } + for (Map.Entry entry : handler.aggMap.entrySet()) + { + aggMap.put( entry.getKey(), entry.getValue()); + } + return this; + } + + /** + * Get the query we are executing against. + * @return the query. + */ + public Query getQuery() + { + return query; + } + + @Override + public void setVars(Map values) { + // nothing to do + + } + + @Override + public void build() { + for (Map.Entry entry : query.getProject().getExprs().entrySet()) + { + if (aggMap.containsKey(entry.getKey())) + { + entry.setValue( aggMap.get(entry.getKey())); + } + } + } + + /** + * Add and expression aggregator and variable to the mapping. + * + * if the expr parameter is not an instance of ExprAggregator then no action is taken. + * + * @param expr The expression to add. + * @param var The variable that it is bound to. + */ + public void add(Expr expr, Var var) { + if (expr instanceof ExprAggregator) + { + ExprAggregator eAgg = (ExprAggregator)expr; + Expr expr2 = query.allocAggregate( eAgg.getAggregator() ); + aggMap.put(var, (ExprAggregator)expr2); + } + } + +} diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/HandlerBlock.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/HandlerBlock.java new file mode 100644 index 00000000000..41c7e42fb92 --- /dev/null +++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/HandlerBlock.java @@ -0,0 +1,268 @@ +package org.apache.jena.arq.querybuilder.handlers; + +/* + * 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. + */ +import java.util.Map; +import org.apache.jena.graph.Node; +import org.apache.jena.query.Query; +import org.apache.jena.sparql.core.Var; + +/** + * A class to handle all the handlers of a query builder and keep them in sync + * as needed. + * + */ +public class HandlerBlock { + private final AggregationHandler aggHandler; + private final ConstructHandler constructHandler; + private final DatasetHandler datasetHandler; + private final PrologHandler prologHandler; + private final SelectHandler selectHandler; + private final SolutionModifierHandler modifierHandler; + private final WhereHandler whereHandler; + + /** + * Constructor. + * + * @param query + * The query we are working with. + */ + public HandlerBlock(Query query) { + prologHandler = new PrologHandler(query); + aggHandler = new AggregationHandler(query); + whereHandler = new WhereHandler(query); + datasetHandler = new DatasetHandler(query); + modifierHandler = new SolutionModifierHandler(query); + /* + * selecthandler and constructhandler may be null so processthem + * accordingly + */ + SelectHandler sTemp = null; + ConstructHandler cTemp = null; + if (query.isSelectType()) { + sTemp = new SelectHandler(aggHandler); + } else if (query.isAskType()) { + // nochange + } else if (query.isDescribeType()) { + // no change + } else if (query.isConstructType()) { + cTemp = new ConstructHandler(query); + } + selectHandler = sTemp; + constructHandler = cTemp; + } + + /** + * Get the aggregation handler. + * + * @return the aggregation handler. + */ + public AggregationHandler getAggregationHandler() { + return aggHandler; + } + + /** + * Get the construct handler. + * + * @return the construct handler or null. + */ + public ConstructHandler getConstructHandler() { + return constructHandler; + } + + /** + * Get the dataset handler. + * + * @return the dataset handler. + */ + public DatasetHandler getDatasetHandler() { + return datasetHandler; + } + + /** + * Get the prolog handler. + * + * @return the prolog handler. + */ + public PrologHandler getPrologHandler() { + return prologHandler; + } + + /** + * Get the select handler. + * + * @return the select handler or null. + */ + public SelectHandler getSelectHandler() { + return selectHandler; + } + + /** + * Get the solution modifier handler. + * + * @return the solution modifier handler. + */ + public SolutionModifierHandler getModifierHandler() { + return modifierHandler; + } + + /** + * Get the where handler. + * + * @return the where handler. + */ + public WhereHandler getWhereHandler() { + return whereHandler; + } + + /** + * Add the prolog handler contents to this prolog handler. + * + * @param handler + * The prolog handler to add to this one. + */ + public void addAll(PrologHandler handler) { + prologHandler.addAll(handler); + } + + /** + * Add the aggregation handler contents to this prolog handler. + * + * @param handler + * The aggregation handler to add to this one. + */ + public void addAll(AggregationHandler handler) { + aggHandler.addAll(handler); + } + + /** + * Add the construct handler contents to this prolog handler. If this + * construct handler is null or the handler argument is null this method + * does nothing. + * + * @param handler + * The construct handler to add to this one. + */ + public void addAll(ConstructHandler handler) { + if (constructHandler != null && handler != null) { + constructHandler.addAll(handler); + } + } + + /** + * Add the dataset handler contents to this prolog handler. + * + * @param handler + * The dataset handler to add to this one. + */ + public void addAll(DatasetHandler handler) { + datasetHandler.addAll(handler); + } + + /** + * Add the solution modifier handler contents to this prolog handler. + * + * @param handler + * The solution modifier handler to add to this one. + */ + public void addAll(SolutionModifierHandler handler) { + modifierHandler.addAll(handler); + } + + /** + * Add the select handler contents to this prolog handler. If this select + * handler is null or the handler argument is null this method does nothing. + * + * @param handler + * The construct handler to add to this one. + */ + public void addAll(SelectHandler handler) { + if (selectHandler != null && handler != null) { + selectHandler.addAll(handler); + } + } + + /** + * Add the where handler contents to this prolog handler. + * + * @param handler + * The where handler to add to this one. + */ + public void addAll(WhereHandler handler) { + whereHandler.addAll(handler); + } + + /** + * Add all of the handlers in the handler block to this one. Any handler + * that is null or is null in the handler argument are properly skipped. + * + * @param handler + * The handler block to add to this one. + */ + public void addAll(HandlerBlock handler) { + addAll(handler.aggHandler); + addAll(handler.constructHandler); + addAll(handler.selectHandler); + addAll(handler.datasetHandler); + addAll(handler.modifierHandler); + addAll(handler.prologHandler); + addAll(handler.whereHandler); + } + + /** + * Set the variables in all the enclosed handlers in the proper order. + * + * @param values + * The map of values to set. + */ + public void setVars(Map values) { + aggHandler.setVars(values); + + if (constructHandler != null) { + constructHandler.setVars(values); + } + + datasetHandler.setVars(values); + prologHandler.setVars(values); + + if (selectHandler != null) { + selectHandler.setVars(values); + } + + modifierHandler.setVars(values); + whereHandler.setVars(values); + } + + /** + * Build all the the enclosed handlers in the proper order. + */ + public void build() { + prologHandler.build(); + + if (selectHandler != null) { + selectHandler.build(); + } + if (constructHandler != null) { + constructHandler.build(); + } + datasetHandler.build(); + modifierHandler.build(); + whereHandler.build(); + aggHandler.build(); + } +} diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/PrologHandler.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/PrologHandler.java index 37629d7c1bf..0a5b1b94637 100644 --- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/PrologHandler.java +++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/PrologHandler.java @@ -24,6 +24,7 @@ import org.apache.jena.query.Query ; import org.apache.jena.riot.system.IRIResolver; import org.apache.jena.shared.PrefixMapping ; +import org.apache.jena.shared.impl.PrefixMappingImpl; import org.apache.jena.sparql.core.Var ; /** @@ -82,6 +83,13 @@ public void setBase(String base) { public void addPrefix(String pfx, String uri) { query.setPrefix(canonicalPfx(pfx), uri); } + + /** + * Clear the prefix mapping. + */ + public void clearPrefixes() { + query.setPrefixMapping( new PrefixMappingImpl() ); + } /** * Add the map of prefixes to the query prefixes. @@ -92,6 +100,10 @@ public void addPrefixes(Map prefixes) { addPrefix(e.getKey(), e.getValue()); } } + + public PrefixMapping getPrefixes() { + return query.getPrefixMapping(); + } /** * Add prefixes from a prefix mapping. 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 index 2d0904bc01a..8875cd3e070 100644 --- 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 @@ -20,7 +20,6 @@ import java.io.StringReader; import java.util.List; import java.util.Map; - import org.apache.jena.graph.Node; import org.apache.jena.query.Query; import org.apache.jena.query.QueryParseException; @@ -39,15 +38,16 @@ public class SelectHandler implements Handler { // the query to handle private final Query query; + private final AggregationHandler aggHandler; /** * Constructor. * - * @param query - * The query to manage. + * @param aggHandler The aggregate handler that wraps the query we want to handle. */ - public SelectHandler(Query query) { - this.query = query; + public SelectHandler(AggregationHandler aggHandler) { + this.query = aggHandler.getQuery(); + this.aggHandler = aggHandler; setDistinct(query.isDistinct()); setReduced(query.isReduced()); } @@ -113,9 +113,12 @@ public void addVar(String expression, Var var) { * Parse an expression string into an expression. * * This must be able to be parsed as though it were written "SELECT "+s - * @param s the select string to parse. + * + * @param s + * the select string to parse. * @return the epxression - * @throws QueryParseException on error + * @throws QueryParseException + * on error */ private Expr parseExpr(String s) throws QueryParseException { try { @@ -142,7 +145,7 @@ private Expr parseExpr(String s) throws QueryParseException { * Add an Expression as variable to the select. * * @param expr - * The expresson to add. + * The expression to add. * @param var * The variable to add. */ @@ -155,6 +158,7 @@ public void addVar(Expr expr, Var var) { } query.setQueryResultStar(false); query.addResultVar(var, expr); + aggHandler.add( expr, var ); } /** @@ -169,7 +173,7 @@ public List getVars() { /** * Return the projected var expression list. * - * @return The proejct var expression list. + * @return The projected var expression list. */ public VarExprList getProject() { return query.getProject(); @@ -182,7 +186,6 @@ public VarExprList getProject() { * 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()); @@ -194,6 +197,7 @@ public void addAll(SelectHandler selectHandler) { qProjectVars.add(var, shProjectVars.getExpr(var)); } } + aggHandler.addAll( selectHandler.aggHandler ); } @Override @@ -206,6 +210,9 @@ public void build() { if (query.getProject().getVars().isEmpty()) { query.setQueryResultStar(true); } + + aggHandler.build(); + // handle the SELECT * case query.getProjectVars(); } 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 index 0a4d4c9c626..83cd469d4dc 100644 --- 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 @@ -20,17 +20,14 @@ import java.util.Collections; import java.util.List; import java.util.Map; - import org.apache.jena.arq.querybuilder.AbstractQueryBuilder; import org.apache.jena.arq.querybuilder.SelectBuilder; -import org.apache.jena.arq.querybuilder.clauses.ConstructClause; import org.apache.jena.arq.querybuilder.rewriters.ElementRewriter; import org.apache.jena.graph.Node; import org.apache.jena.graph.NodeFactory; import org.apache.jena.graph.Triple; import org.apache.jena.query.Query; import org.apache.jena.sparql.core.Var; -import org.apache.jena.sparql.core.VarExprList; import org.apache.jena.sparql.expr.Expr; import org.apache.jena.sparql.lang.sparql_11.ParseException; import org.apache.jena.sparql.syntax.*; @@ -220,6 +217,10 @@ public void addOptional(Triple t) throws IllegalArgumentException { getClause().addElement(opt); } + /** + * Add the contents of a where handler as an optional statement. + * @param whereHandler The where handler to use as the optional statement. + */ public void addOptional(WhereHandler whereHandler) { getClause().addElement(new ElementOptional(whereHandler.getClause())); } @@ -263,28 +264,29 @@ public void addSubQuery(SelectBuilder subQuery) { * The sub query to convert * @return THe converted element. */ - private ElementSubQuery makeSubQuery(SelectBuilder subQuery) { + private ElementSubQuery makeSubQuery(AbstractQueryBuilder subQuery) { Query q = new Query(); - PrologHandler ph = new PrologHandler(query); - ph.addAll(subQuery.getPrologHandler()); - - VarExprList vars = subQuery.getSelectHandler().getProject(); - for (Var v : vars.getVars()) { - q.addResultVar(v, vars.getExpr(v)); - q.setQuerySelectType(); + SelectHandler sh = subQuery.getHandlerBlock().getSelectHandler(); + if (sh != null) + { + if (! sh.getProject().isEmpty()) { + q.setQuerySelectType(); + } } - - if (subQuery instanceof ConstructClause) { - ConstructHandler ch = new ConstructHandler(q); - ch.addAll(((ConstructClause) subQuery).getConstructHandler()); - + PrologHandler ph = new PrologHandler(query); + ph.addPrefixes( subQuery.getPrologHandler().getPrefixes() ); + HandlerBlock handlerBlock = new HandlerBlock(q); + handlerBlock.addAll( subQuery.getHandlerBlock() ); + // remove the prefix mappings from the sub query. + handlerBlock.getPrologHandler().clearPrefixes(); + + + // make sure we have a query pattern before we start building. + if (q.getQueryPattern() == null) + { + q.setQueryPattern( new ElementGroup() ); } - DatasetHandler dh = new DatasetHandler(q); - dh.addAll(subQuery.getDatasetHandler()); - SolutionModifierHandler smh = new SolutionModifierHandler(q); - smh.addAll(subQuery.getSolutionModifierHandler()); - WhereHandler wh = new WhereHandler(q); - wh.addAll(subQuery.getWhereHandler()); + handlerBlock.build(); return new ElementSubQuery(q); } @@ -320,7 +322,7 @@ public void addUnion(SelectBuilder subQuery) { union.addElement(makeSubQuery(subQuery)); } else { PrologHandler ph = new PrologHandler(query); - ph.addAll(subQuery.getPrologHandler()); + ph.addPrefixes(subQuery.getPrologHandler().getPrefixes()); union.addElement(subQuery.getWhereHandler().getClause()); } 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 index 91acce25c8e..4a9a56ac3d9 100644 --- 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 @@ -23,6 +23,7 @@ import org.apache.jena.arq.querybuilder.AbstractQueryBuilder; import org.apache.jena.graph.Node ; import org.apache.jena.graph.Triple ; +import org.apache.jena.query.Query; import org.apache.jena.sparql.core.TriplePath ; import org.apache.jena.sparql.core.Var ; import org.apache.jena.sparql.engine.binding.Binding ; @@ -190,8 +191,9 @@ public void visit(ElementService el) { @Override public void visit(ElementSubQuery el) { + Query q = AbstractQueryBuilder.clone(el.getQuery()); push(new ElementSubQuery(AbstractQueryBuilder.rewrite( - AbstractQueryBuilder.clone(el.getQuery()), values))); + q, values))); } } \ No newline at end of file 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 index 4293a6f5a2f..89108a9e46e 100644 --- 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 @@ -19,11 +19,15 @@ package org.apache.jena.arq.querybuilder; import static org.junit.Assert.*; + +import org.apache.jena.arq.querybuilder.handlers.HandlerBlock; +import org.apache.jena.arq.querybuilder.handlers.PrologHandler; import org.apache.jena.graph.FrontsNode ; import org.apache.jena.graph.Node ; import org.apache.jena.graph.NodeFactory ; import org.apache.jena.graph.impl.LiteralLabel ; import org.apache.jena.graph.impl.LiteralLabelFactory ; +import org.apache.jena.query.Query; import org.apache.jena.reasoner.rulesys.Node_RuleVariable ; import org.apache.jena.sparql.core.Var ; import org.apache.jena.sparql.expr.ExprVar ; @@ -41,10 +45,23 @@ public void setup() { } private class TestBuilder extends AbstractQueryBuilder { + private HandlerBlock handlerBlock; + + public TestBuilder() + { + super(); + handlerBlock = new HandlerBlock( query ); + + } @Override public String toString() { return "TestBuilder"; } + + @Override + public HandlerBlock getHandlerBlock() { + return handlerBlock; + } } private class NodeFront implements FrontsNode { 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 index 535be17acd9..3eb209f3187 100644 --- 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 @@ -18,20 +18,32 @@ package org.apache.jena.arq.querybuilder; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.apache.jena.arq.AbstractRegexpBasedTest; -import org.apache.jena.sparql.core.Var ; -import org.apache.jena.vocabulary.RDF ; +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryExecution; +import org.apache.jena.query.QueryExecutionFactory; +import org.apache.jena.query.QueryFactory; +import org.apache.jena.query.QuerySolution; +import org.apache.jena.query.ResultSet; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.lang.sparql_11.ParseException; +import org.apache.jena.vocabulary.RDF; +import org.apache.jena.vocabulary.XSD; import org.junit.Before; import org.junit.Test; public class SelectBuilderTest extends AbstractRegexpBasedTest { private SelectBuilder builder; - - @Before + + @Before public void setup() { builder = new SelectBuilder(); } @@ -40,23 +52,18 @@ public void setup() { 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 - + CLOSE_CURLY, builder.buildString()); + assertContainsRegex(SELECT + "\\*" + SPACE + WHERE + OPEN_CURLY + var("s") + SPACE + var("p") + SPACE + var("o") + + OPT_SPACE + CLOSE_CURLY, builder.buildString()); builder.setVar(Var.alloc("p"), RDF.type); - assertContainsRegex(SELECT + "\\*" + SPACE + WHERE + OPEN_CURLY - + var("s") + SPACE - + regexRDFtype - + SPACE + var("o") + OPT_SPACE + CLOSE_CURLY, - builder.buildString()); + assertContainsRegex(SELECT + "\\*" + SPACE + WHERE + OPEN_CURLY + var("s") + SPACE + regexRDFtype + SPACE + + var("o") + OPT_SPACE + 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") + 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(); @@ -67,60 +74,49 @@ public void testAll() { * foaf:Person . * OPTIONAL { ?s foaf:name ?name .} } ORDER BY ?s */ - assertContainsRegex(PREFIX + "foaf:" + SPACE - + uri("http://xmlns.com/foaf/0.1/"), query); + assertContainsRegex(PREFIX + "foaf:" + SPACE + uri("http://xmlns.com/foaf/0.1/"), query); assertContainsRegex(SELECT + var("s"), query); - assertContainsRegex(WHERE + OPEN_CURLY + var("s") + SPACE - + regexRDFtype - + SPACE + "foaf:Person" + SPACE + OPTIONAL - + OPEN_CURLY + var("s") + SPACE + "foaf:name" + SPACE - + var("name") + OPT_SPACE + CLOSE_CURLY + assertContainsRegex(WHERE + OPEN_CURLY + var("s") + SPACE + regexRDFtype + SPACE + "foaf:Person" + SPACE + + OPTIONAL + OPEN_CURLY + var("s") + SPACE + "foaf:name" + SPACE + var("name") + OPT_SPACE + CLOSE_CURLY + CLOSE_CURLY, query); assertContainsRegex(ORDER_BY + var("s"), query); builder.setVar("name", "Smith"); query = builder.buildString(); - assertContainsRegex(PREFIX + "foaf:" + SPACE - + uri("http://xmlns.com/foaf/0.1/"), query); + assertContainsRegex(PREFIX + "foaf:" + SPACE + uri("http://xmlns.com/foaf/0.1/"), query); assertContainsRegex(SELECT + var("s"), query); - assertContainsRegex(WHERE + OPEN_CURLY + var("s") + SPACE - + regexRDFtype - + SPACE + "foaf:Person" + SPACE + OPTIONAL - + OPEN_CURLY + var("s") + SPACE + "foaf:name" + SPACE - + quote("Smith") + presentStringType() + assertContainsRegex(WHERE + OPEN_CURLY + var("s") + SPACE + regexRDFtype + SPACE + "foaf:Person" + SPACE + + OPTIONAL + OPEN_CURLY + var("s") + SPACE + "foaf:name" + SPACE + quote("Smith") + presentStringType() + 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"); + 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 + CLOSE_CURLY, query); + assertContainsRegex(WHERE + OPEN_CURLY + ":S" + SPACE + var("p") + SPACE + ":O" + OPT_SPACE + CLOSE_CURLY, + query); } @Test public void testSubjectVar() { - builder.addVar("*").addPrefix("", "http://example/") - .addWhere("?s", ":P", ":O"); + 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 + CLOSE_CURLY, query); + assertContainsRegex(WHERE + OPEN_CURLY + var("s") + SPACE + ":P" + SPACE + ":O" + OPT_SPACE + CLOSE_CURLY, + query); } @Test public void testObjectVar() { - builder.addVar("*").addPrefix("", "http://example/") - .addWhere(":S", ":P", "?o"); + 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 + CLOSE_CURLY, query); + assertContainsRegex(WHERE + OPEN_CURLY + ":S" + SPACE + ":P" + SPACE + var("o") + OPT_SPACE + CLOSE_CURLY, + query); } @Test @@ -130,37 +126,149 @@ public void testNoVars() { assertContainsRegex(SELECT + "\\*" + SPACE, query); } - + @Test public void testList() { - builder.addVar( "*" ) - .addWhere( builder.list( "", "?two", "'three'"), "", ""); + builder.addVar("*").addWhere(builder.list("", "?two", "'three'"), "", ""); String query = builder.buildString(); - - assertContainsRegex( - "_:b0"+SPACE+ uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#first") + SPACE + uri("one") + SEMI - + SPACE + uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest") + SPACE+"_:b1"+ DOT - + SPACE + "_:b1"+SPACE+ uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#first") + SPACE + var("two") + SEMI - + SPACE + uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest") + SPACE+"_:b2"+ DOT - + SPACE + "_:b2"+SPACE+ uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#first") + SPACE + quote("three") + SEMI - + SPACE + uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest") + SPACE +uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil") - , query); - - assertContainsRegex( - "_:b0"+SPACE+ uri("foo") + SPACE + uri("bar"), query); + + assertContainsRegex("_:b0" + SPACE + uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#first") + SPACE + + uri("one") + SEMI + SPACE + uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest") + SPACE + "_:b1" + + DOT + SPACE + "_:b1" + SPACE + uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#first") + SPACE + + var("two") + SEMI + SPACE + uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest") + SPACE + "_:b2" + + DOT + SPACE + "_:b2" + SPACE + uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#first") + SPACE + + quote("three") + SEMI + SPACE + uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest") + SPACE + + uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"), query); + + assertContainsRegex("_:b0" + SPACE + uri("foo") + SPACE + uri("bar"), query); } - + @Test public void testClone() { - builder.addVar( "*" ) - .addWhere( "?two", "", ""); + builder.addVar("*").addWhere("?two", "", ""); SelectBuilder builder2 = builder.clone(); - builder2.addOrderBy( "?two"); - + builder2.addOrderBy("?two"); + String q1 = builder.buildString(); String q2 = builder2.buildString(); + + assertTrue(q2.contains("ORDER BY")); + assertFalse(q1.contains("ORDER BY")); + } + + @Test + public void testAggregatorsInSelect() throws ParseException { + builder.addVar("?x").addVar("count(*)", "?c").addWhere("?x", "?p", "?o").addGroupBy("?x"); + + Model m = ModelFactory.createDefaultModel(); + Resource r = m.createResource("urn:one"); + m.add(r, m.getProperty("urn:p:one"), m.createTypedLiteral(1)); + m.add(r, m.getProperty("urn:p:two"), m.createTypedLiteral(3)); + m.add(r, m.getProperty("urn:p:three"), m.createTypedLiteral(5)); + r = m.createResource("urn:two"); + m.add(r, m.getProperty("urn:p:one"), m.createTypedLiteral(1)); + m.add(r, m.getProperty("urn:p:two"), m.createTypedLiteral(3)); + m.add(r, m.getProperty("urn:p:three"), m.createTypedLiteral(5)); + + QueryExecution qexec = QueryExecutionFactory.create(builder.build(), m); + + ResultSet results = qexec.execSelect(); + assertTrue(results.hasNext()); + for (; results.hasNext();) { + QuerySolution soln = results.nextSolution(); + assertTrue(soln.contains("c")); + assertTrue(soln.contains("x")); + assertEquals(3, soln.get("c").asLiteral().getInt()); + } + + builder.addVar("min(?o)", "?min").addVar("max(?o)", "?max"); + + qexec = QueryExecutionFactory.create(builder.build(), m); + + results = qexec.execSelect(); + assertTrue(results.hasNext()); + for (; results.hasNext();) { + QuerySolution soln = results.nextSolution(); + assertTrue(soln.contains("c")); + assertTrue(soln.contains("x")); + assertTrue(soln.contains("?min")); + assertEquals(3, soln.get("c").asLiteral().getInt()); + assertEquals(1, soln.get("min").asLiteral().getInt()); + assertEquals(5, soln.get("max").asLiteral().getInt()); + } + + } + + @Test + public void testAggregatorsInSubQuery() throws ParseException { + + Model m = ModelFactory.createDefaultModel(); + Resource r = m.createResource("urn:one"); + m.add(r, m.getProperty("urn:p:one"), m.createTypedLiteral(1)); + m.add(r, m.getProperty("urn:p:two"), m.createTypedLiteral(3)); + m.add(r, m.getProperty("urn:p:three"), m.createTypedLiteral(5)); + r = m.createResource("urn:two"); + m.add(r, m.getProperty("urn:p:one"), m.createTypedLiteral(2)); + m.add(r, m.getProperty("urn:p:two"), m.createTypedLiteral(4)); + m.add(r, m.getProperty("urn:p:three"), m.createTypedLiteral(6)); + + SelectBuilder sb = new SelectBuilder().addVar("?x").addVar("max(?o)", "?max").addWhere("?x", "?p", "?o") + .addGroupBy("?x"); + + builder.addPrefix("xsd", XSD.getURI()).addVar("?x").addVar("min(?o2)", "?min").addWhere("?x", "?p2", "?o2") + .addSubQuery(sb).addFilter("?max = '6'^^xsd:int").addGroupBy("?x"); + + QueryExecution qexec = QueryExecutionFactory.create(builder.build(), m); + + ResultSet results = qexec.execSelect(); + assertTrue(results.hasNext()); + for (; results.hasNext();) { + QuerySolution soln = results.nextSolution(); + assertTrue(soln.contains("x")); + assertTrue(soln.contains("min")); + assertEquals("urn:two", soln.get("?x").asResource().getURI()); + assertEquals(2, soln.get("?min").asLiteral().getInt()); + } + } + + @Test + public void testVarReplacementInSubQuery() throws ParseException { + + Model m = ModelFactory.createDefaultModel(); + Resource r = m.createResource("urn:one"); + m.add(r, m.getProperty("urn:p:one"), m.createTypedLiteral(1)); + m.add(r, m.getProperty("urn:p:two"), m.createTypedLiteral(3)); + m.add(r, m.getProperty("urn:p:three"), m.createTypedLiteral(5)); + r = m.createResource("urn:two"); + m.add(r, m.getProperty("urn:p:one"), m.createTypedLiteral(2)); + m.add(r, m.getProperty("urn:p:two"), m.createTypedLiteral(4)); + m.add(r, m.getProperty("urn:p:three"), m.createTypedLiteral(6)); + + SelectBuilder sb = new SelectBuilder().addVar("?x").addVar("?p").addWhere("?x", "?p", "?o") + .addFilter( "?o < ?limit"); + + builder.addPrefix("xsd", XSD.getURI()).addVar("?x").addVar("count(?p)", "?c").addWhere("?x", "?p", "?o2") + .addSubQuery(sb).addGroupBy("?x"); + - assertTrue( q2.contains("ORDER BY")); - assertFalse( q1.contains("ORDER BY")); + builder.setVar( "?limit", 4 ); + + QueryExecution qexec = QueryExecutionFactory.create(builder.build(), m); + + ResultSet results = qexec.execSelect(); + assertTrue(results.hasNext()); + for (; results.hasNext();) { + QuerySolution soln = results.nextSolution(); + assertTrue(soln.contains("x")); + assertTrue(soln.contains("c")); + if ("urn:one".equals( soln.get("?x").asResource().getURI())) + { + assertEquals( 2, soln.get("?c").asLiteral().getInt()); + } + else + { + assertEquals( 1, soln.get("?c").asLiteral().getInt()); + } + } } } diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/WhereClauseTest.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/WhereClauseTest.java index 570a91ef341..23b522bd1d5 100644 --- a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/WhereClauseTest.java +++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/clauses/WhereClauseTest.java @@ -144,7 +144,7 @@ public void testAddFilter() throws ParseException { } @ContractTest - public void addSubQuery() { + public void testAddSubQuery() { SelectBuilder sb = new SelectBuilder(); sb.addPrefix("pfx", "urn:uri").addVar("?x") .addWhere("pfx:one", "pfx:two", "pfx:three"); diff --git a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/SelectHandlerTest.java b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/SelectHandlerTest.java index 4e514784a6d..6e131deffa5 100644 --- a/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/SelectHandlerTest.java +++ b/jena-extras/jena-querybuilder/src/test/java/org/apache/jena/arq/querybuilder/handlers/SelectHandlerTest.java @@ -38,7 +38,8 @@ public class SelectHandlerTest extends AbstractHandlerTest { @Before public void setup() { query = new Query(); - handler = new SelectHandler(query); + AggregationHandler aggHandler = new AggregationHandler(query); + handler = new SelectHandler(aggHandler); } @Test @@ -166,7 +167,8 @@ public void testSetReduced() { @Test public void testAddAllResultStartReduced() { - SelectHandler sh = new SelectHandler(new Query()); + AggregationHandler aggHandler = new AggregationHandler(new Query()); + SelectHandler sh = new SelectHandler(aggHandler); sh.addVar(null); sh.setReduced(true); @@ -177,7 +179,8 @@ public void testAddAllResultStartReduced() { @Test public void testAddAllVarsDistinct() { - SelectHandler sh = new SelectHandler(new Query()); + AggregationHandler aggHandler = new AggregationHandler(new Query()); + SelectHandler sh = new SelectHandler(aggHandler); sh.addVar(Var.alloc("foo")); sh.setDistinct(true);