/* * Copyright (c) 1998-2009, The University of Sheffield. * * This file is part of GATE (see http://gate.ac.uk/), and is free * software, licenced under the GNU Library General Public License, * Version 2, June 1991 (in the distribution as file licence.html, * and also available at http://gate.ac.uk/gate/licence.html). * * Johann Petrak 2009-08-13 * * $Id: UtilTupleQueryIterator.java 11700 2009-10-21 09:26:23Z johann_p $ */ package gate.creole.ontology.impl.sesame; import gate.creole.ontology.GateOntologyException; import gate.creole.ontology.LiteralOrONodeID; import gate.creole.ontology.Literal; import gate.creole.ontology.ONodeID; import gate.creole.ontology.OConstants; import gate.creole.ontology.OntologyTupleQuery; import gate.creole.ontology.impl.LiteralOrONodeIDImpl; import java.util.List; import java.util.Vector; import org.apache.log4j.Logger; import org.openrdf.model.BNode; import org.openrdf.model.URI; import org.openrdf.model.Value; import org.openrdf.query.BindingSet; import org.openrdf.query.QueryEvaluationException; import org.openrdf.query.QueryLanguage; import org.openrdf.query.TupleQuery; import org.openrdf.query.TupleQueryResult; import org.openrdf.repository.RepositoryConnection; /** * A class representing a Sesame Query. This class makes it easy to * iterate over query results, reuse a query with different variable * bindings, and provides special methods for queries where only one * column is retrieved. * <p> * The following steps should be carried out when using this class: * <ol> * <li>Create an object and pass on the repository connection, query string, * and query language constant * <li>Set any variables for the query using {@link #setBinding} one or more times * <li>Evaluate the query using {@link evaluate}. This is optional, if not done, * it will be done implicitly in the first call to {@link #hasNext}. * <li>Retrieve query results one by one using one of the next... methods * <li>If no more results are needed the query MUST BE CLOSED using the * {@link #close} function to free the query resources. However, if all * results have been returned and {@link #hasNext()} has returned false, * the query has been closed automatically. It is allowed to call close * on a closed query. * <li>To reuse the query, repeat from step 2 * </ol> * * @author Johann Petrak */ public class UtilTupleQueryIterator implements OntologyTupleQuery { private RepositoryConnection mRepositoryConnection; private String mQuery; private TupleQueryResult mResult; private TupleQuery mTupleQuery; private Vector<String> mVarnames; private QueryLanguage mLang = QueryLanguage.SERQL; private boolean mIsClosed = true; private boolean mIsPrepared = false; private boolean mIsEvaluated = false; private Logger logger; public UtilTupleQueryIterator(RepositoryConnection repositoryConnection, String query, OConstants.QueryLanguage queryLanguage) { if(queryLanguage == OConstants.QueryLanguage.SPARQL) { mLang = QueryLanguage.SPARQL; } else if(queryLanguage == OConstants.QueryLanguage.SERQL) { mLang = QueryLanguage.SERQL; } else { throw new GateOntologyException("Query language must be SPARQL or SERQL, got "+queryLanguage); } //System.out.println("Created tuple query object: "+query); logger = Logger.getLogger(this.getClass().getName()); mRepositoryConnection = repositoryConnection; logger.debug("Creating query: " + query); mQuery = query; prepare(); } public void prepare() { try { mTupleQuery = mRepositoryConnection.prepareTupleQuery(mLang, mQuery); } catch (Exception e) { throw new GateOntologyException("Cannot prepare tuple query: "+mQuery, e); } mIsPrepared = true; } /** * * @param name * @param value */ public void setBinding(String name, Value value) { mTupleQuery.setBinding(name, value); } public void setBinding(String name, LiteralOrONodeID value) { mTupleQuery.setBinding(name, UtilConvert.toSesameValue(value)); } public void setBinding(String name, Literal value) { mTupleQuery.setBinding(name, UtilConvert.toSesameLiteral(value)); } public void setBinding(String name, ONodeID value) { mTupleQuery.setBinding(name, UtilConvert.toSesameValue(value)); } /** * */ public void evaluate() { close(); if (!mIsPrepared) { prepare(); } try { mResult = mTupleQuery.evaluate(); mIsClosed = false; List<String> varnamesList = mResult.getBindingNames(); mVarnames = new Vector<String>(varnamesList); } catch (Exception e) { throw new GateOntologyException("Cannot evaluate queyr: "+mQuery, e); } mIsEvaluated = true; } public boolean hasNext() { if (!mIsPrepared) { prepare(); } if (!mIsEvaluated) { evaluate(); } try { boolean hasnext = mResult.hasNext(); if(!hasnext) { close(); } return hasnext; } catch (QueryEvaluationException e) { throw new GateOntologyException("Error checking for next result of query", e); } } public String nextFirstAsString() { String ret = nextFirstAsValue().stringValue(); //logger.debug("QS: "+ret); return ret; } public LiteralOrONodeID nextFirst() { Value v = nextFirstAsValue(); if(v instanceof BNode) { return new LiteralOrONodeIDImpl(new OBNodeIDImpl(v.stringValue())); } else if(v instanceof org.openrdf.model.Literal) { return new LiteralOrONodeIDImpl( UtilConvert.toGateLiteral((org.openrdf.model.Literal)v)); } else if(v instanceof org.openrdf.model.URI) { URI u = (URI)v; // TODO: check if we want toString or stringValue() here return new LiteralOrONodeIDImpl(new OURIImpl(u.stringValue())); } return null; } public Value nextFirstAsValue() { if (mResult == null) { throw new GateOntologyException("No prepared query available"); } Value ret; try { BindingSet bindingSet = mResult.next(); ret = bindingSet.getValue(mVarnames.get(0)); } catch (QueryEvaluationException e) { throw new GateOntologyException("Could not get next query result", e); } //logger.debug("QV: "+ret); return ret; } public Vector<Value> nextAsValue() { if(!hasNext()) { throw new GateOntologyException("No more query results but next was called"); } Vector<Value> result = new Vector<Value>(); try { BindingSet bindingSet = mResult.next(); for (String bindingName : mVarnames) { Value value = bindingSet.getValue(bindingName); result.add(value); } } catch (QueryEvaluationException e) { throw new GateOntologyException("Could not get next query result", e); } logger.debug("Qvec: " + result); return result; } public Vector<String> nextAsString() { if (!hasNext()) { throw new GateOntologyException("No more query results but next was called"); } Vector<String> result = new Vector<String>(); try { BindingSet bindingSet = mResult.next(); for (String bindingName : mVarnames) { Value value = bindingSet.getValue(bindingName); String val = value.stringValue(); result.add(val); } } catch (QueryEvaluationException e) { throw new GateOntologyException("Could not get next query result", e); } return result; } public Vector<LiteralOrONodeID> next() { if(!hasNext()) { throw new GateOntologyException("No more query results but next was called"); } Vector<LiteralOrONodeID> result = new Vector<LiteralOrONodeID>(); try { BindingSet bindingSet = mResult.next(); for (String bindingName : mVarnames) { Value value = bindingSet.getValue(bindingName); if(value instanceof BNode) { result.add(new LiteralOrONodeIDImpl(new OBNodeIDImpl(value.stringValue()))); } else if(value instanceof org.openrdf.model.Literal) { result.add(new LiteralOrONodeIDImpl( UtilConvert.toGateLiteral((org.openrdf.model.Literal)value))); } else if(value instanceof org.openrdf.model.URI) { URI u = (URI)value; result.add(new LiteralOrONodeIDImpl(new OURIImpl(u.stringValue()))); } } } catch (QueryEvaluationException e) { throw new GateOntologyException("Could not get next query result", e); } logger.debug("Qvec: " + result); return result; } public void close() { try { if (!mIsClosed) { mResult.close(); mIsEvaluated = false; mIsClosed = true; } } catch (Exception e) { throw new GateOntologyException("Error closing query " + mQuery, e); } } public void remove() { throw new UnsupportedOperationException("remove method not supported"); } }