package org.aksw.jena_sparql_api.core; import java.util.Iterator; import org.aksw.commons.collections.SinglePrefetchIterator; import org.aksw.jena_sparql_api.utils.CloseableQueryExecution; import org.aksw.jena_sparql_api.utils.QueryUtils; import org.apache.jena.graph.Node; import org.apache.jena.graph.Triple; import org.apache.jena.query.Query; import org.apache.jena.query.QueryExecution; import org.apache.jena.query.QueryFactory; 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.Statement; import org.apache.jena.sparql.syntax.Template; import org.apache.jena.update.UpdateRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class IteratorWrapperClose<T> extends SinglePrefetchIterator<T> { private Iterator<T> it; public IteratorWrapperClose(Iterator<T> it) { this.it = it; } @Override protected T prefetch() throws Exception { if(!it.hasNext()) { return finish(); } else { T result = it.next(); return result; } } } class TestQueryExecutionBaseSelect extends QueryExecutionBaseSelect { public TestQueryExecutionBaseSelect(Query query) { super(query, null); } @Override protected QueryExecution executeCoreSelectX(Query query) { System.out.println("Got a query string: " + query); return null; } public static void main(String[] args) { Query query = QueryFactory.create("Describe ?x <http://aaaa> {?x a <http://blah> .}"); query = QueryFactory.create("Describe <http://aaaa>"); query = QueryFactory.create("Describe"); TestQueryExecutionBaseSelect x = new TestQueryExecutionBaseSelect(query); x.execDescribe(); } } /** * A Sparqler-class that implements ask, describe, and construct * based on the executeCoreSelect(Query) method. * * Also, works on String and Query level. * * Some of the code has been taken from * org.apache.jena.sparql.engine.QueryExecutionBase, which is a * class with a similar purpose but not as reusable as this one * (This class reduces all operations to a single executeCoreSelect call) * * NOTE: executeCoreSelect will close this query execution once the ResultSet is consumed. * * @author raven * */ public abstract class QueryExecutionBaseSelect extends QueryExecutionDecorator implements QueryExecution { private static final Logger logger = LoggerFactory .getLogger(QueryExecutionBaseSelect.class); protected Query query; // Describe queries are sent as multiple individual queries, therefore we require a // back reference to the corresponding QueryExecutionFactory protected QueryExecutionFactory parentFactory; // TODO Move these two utility methods to a utility class // Either the whole Sparql API should go to the jena module // or it needs a dependency on that module... public static Model createModel(Iterator<Triple> it) { return createModel(ModelFactory.createDefaultModel(), it); } public static Model createModel(Model result, Iterator<Triple> it) { while(it.hasNext()) { Triple t = it.next(); Statement stmt = org.apache.jena.sparql.util.ModelUtils.tripleToStatement(result, t); if (stmt != null) { result.add(stmt); } } return result; } public QueryExecutionBaseSelect(Query query, QueryExecutionFactory subFactory) { super(null); this.query = query; this.parentFactory = subFactory; } //private QueryExecution running = null; abstract protected QueryExecution executeCoreSelectX(Query query); protected ResultSetCloseable executeCoreSelect(Query query) { if(this.decoratee != null) { throw new RuntimeException("A query is already running"); } this.decoratee = executeCoreSelectX(query); if(this.decoratee == null) { throw new RuntimeException("Failed to obtain a QueryExecution for query: " + query); } //return decoratee.execSelect(); ResultSet tmp = decoratee.execSelect(); final QueryExecution self = this; ResultSetCloseable result = new ResultSetCloseable(tmp, new CloseableQueryExecution(self)); return result; } // Note: The super class already closes the decoratee // @Override // public void close() { // decoratee.close(); // } @Override public boolean execAsk() { if (!query.isAskType()) { throw new RuntimeException("ASK query expected. Got: [" + query.toString() + "]"); } Query selectQuery = QueryUtils.elementToQuery(query.getQueryPattern()); selectQuery.setLimit(1); ResultSet rs = executeCoreSelect(selectQuery); long rowCount = 0; while(rs.hasNext()) { rs.next(); ++rowCount; } if (rowCount > 1) { logger.warn("Received " + rowCount + " rows for the query [" + query.toString() + "]"); } return rowCount > 0; } @Override public Model execDescribe() { Model model = ModelFactory.createDefaultModel(); return execDescribe(model); } public static Node extractDescribeNode(Query query) { if (!query.isDescribeType()) { throw new RuntimeException("DESCRIBE query expected. Got: [" + query.toString() + "]"); } // TODO Right now we only support describe with a single constant. //Element queryPattern = query.getQueryPattern(); if(query.getQueryPattern() != null || !query.getResultVars().isEmpty() || query.getResultURIs().size() > 1) { throw new RuntimeException("Sorry, DESCRIBE is only implemented for a single resource argument"); } Node result = query.getResultURIs().get(0); return result; } /** * We use this query execution for retrieving the result set of the * where clause, but we neet the subFactory to describe the individual * resources then. * * @return */ @Override public Iterator<Triple> execDescribeTriples() { ResultSetCloseable rs = null; if ( query.getQueryPattern() != null ) { Query q = new Query(); q.setQuerySelectType(); q.setResultVars(); for(String v : query.getResultVars()) { q.addResultVar(v); } q.setQueryPattern(query.getQueryPattern()); rs = this.executeCoreSelect(q); } // Note: We need to close the connection when we are done Describer tmp = Describer.create(query.getResultURIs(), query.getResultVars(), rs, parentFactory); final QueryExecution self = this; Iterator<Triple> result = new IteratorWrapperClose<Triple>(tmp) { @Override public void close() { self.close(); } }; return result; } /** * A describe query is translated into a construct query. * * * * Lets see... * Describe ?a ?b ... <x><y> Where Pattern { ... } becomes ...? * * Construct { ?a ?ap ?ao . ?b ?bp ?bo . } Where Pattern { } Union {} * Ah, lets just query every resource individually for now * * * TODO Add support for concise bounded descriptions... * * @param result * @return */ @Override public Model execDescribe(Model result) { createModel(result, execDescribeTriples()); return result; /* Generator generator = Gensym.create("xx_generated_var_"); Element queryPattern = query.getQueryPattern(); ElementPathBlock pathBlock; if(queryPattern == null) { ElementGroup elementGroup = new ElementGroup(); pathBlock = new ElementPathBlock(); elementGroup.addElement(pathBlock); } else { ElementGroup elementGroup = (ElementGroup)queryPattern; pathBlock = (ElementPathBlock)elementGroup.getElements().get(0); } //Template template = new Template(); //template. BasicPattern basicPattern = new BasicPattern(); System.out.println(queryPattern.getClass()); for(Node node : query.getResultURIs()) { Var p = Var.alloc(generator.next()); Var o = Var.alloc(generator.next()); Triple triple = new Triple(node, p, o); basicPattern.add(); //queryPattern. } for(String var : query.getResultVars()) { } Template template = new Template(basicPattern); Query selectQuery = QueryUtils.elementToQuery(query.getQueryPattern()); ResultSet rs = executeCoreSelect(selectQuery); //throw new RuntimeException("Sorry, DESCRIBE is not implemted yet."); */ } private Iterator<Triple> executeConstructStreaming(Query query) { if (!query.isConstructType()) { throw new RuntimeException("CONSTRUCT query expected. Got: [" + query.toString() + "]"); } Query clone = query.cloneQuery(); clone.setQuerySelectType(); //Query selectQuery = QueryUtils.elementToQuery(query.getQueryPattern()); clone.setQueryResultStar(true); ResultSetCloseable rs = executeCoreSelect(clone); // insertPrefixesInto(result) ; Template template = query.getConstructTemplate(); Iterator<Triple> result = new ConstructIterator(template, rs); return result; } private Model executeConstruct(Query query, Model result) { createModel(result, executeConstructStreaming(query)); return result; } @Override public Model execConstruct(Model result) { return executeConstruct(this.query, result); } @Override public Model execConstruct() { Model result = ModelFactory.createDefaultModel(); execConstruct(result); return result; } @Override public Iterator<Triple> execConstructTriples() { return executeConstructStreaming(this.query); } @Override public ResultSet execSelect() { if (!query.isSelectType()) { throw new RuntimeException("SELECT query expected. Got: [" + query.toString() + "]"); } return executeCoreSelect(query); } //@Override public void executeUpdate(UpdateRequest updateRequest) { throw new RuntimeException("Not implemented"); } }