package edu.mit.simile.fresnel.selection;
import java.util.Iterator;
import java.util.Vector;
import org.openrdf.model.BNode;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.query.GraphQueryResult;
import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.QueryLanguage;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
/**
* Selector based on a SPARQL query.
*
* @author Jörg Koch
*/
public class SPARQLSelector implements ISelector {
/**
* The original SPARQL query.
*/
private String _SPARQL;
/**
* Create an SPARQL selector based on its string representation.
*
* @param query
* The <code>String</code> representation of the SPARQL query
*/
public SPARQLSelector(String query, String namespaces) {
this._SPARQL = namespaces;
this._SPARQL = this._SPARQL.concat(query);
}
/**
* Select statements for the currently selected resource. The ?instance variable is
* called instance as a convention and is replaced by the currently selected resource.
*
* @see edu.mit.simile.fresnel.selection.ISelector#selectStatements(Repository, Resource)
*/
public Iterator<Statement> selectStatements(Repository in, Resource selected) throws InvalidResultSetException {
Vector<Statement> statements = new Vector<Statement>();
String filteredQuery;
try {
RepositoryConnection conn = in.getConnection();
if (selected instanceof BNode) {
filteredQuery = _SPARQL.replace("?instance", "_:" + selected.toString());
} else {
filteredQuery = _SPARQL.replace("?instance", "<" + selected.toString() + ">");
}
GraphQueryResult graphResult = conn.prepareGraphQuery(QueryLanguage.SPARQL, filteredQuery).evaluate();
while (graphResult.hasNext()) {
statements.add(graphResult.next());
}
graphResult.close();
conn.close();
} catch (RepositoryException e) {
throw new InvalidResultSetException("Repository exception encountered selecting statements", e);
} catch (MalformedQueryException e) {
throw new InvalidResultSetException("Bad query encountered selecting statements using " + this._SPARQL, e);
} catch (QueryEvaluationException e) {
throw new InvalidResultSetException("Query evaluation exception encountered selecting statements using " + this._SPARQL, e);
}
return statements.iterator();
}
/**
* @see edu.mit.simile.fresnel.selection.ISelector#canSelectStatements()
*/
public boolean canSelectStatements() {
return true;
}
/**
* @see edu.mit.simile.fresnel.selection.ISelector#canSelect(Repository, Resource)
*/
public boolean canSelect(Repository in, Resource selected) {
try {
Iterator<Resource> ri = selectResources(in);
while (ri.hasNext()) {
if (ri.next().equals(selected))
return true;
}
} catch (InvalidResultSetException e) {
// TODO these exceptions should be logged.
return false;
}
return false;
}
/**
* @see edu.mit.simile.fresnel.selection.ISelector#canSelect(Repository, Resource, URI)
*/
public boolean canSelect(Repository in, Resource selected, URI prop) {
try {
Iterator<Statement> si = selectStatements(in, selected);
while (si.hasNext()) {
if (si.next().getPredicate().equals(prop))
return true;
}
} catch (InvalidResultSetException e) {
// TODO these exceptions should be logged.
return false;
}
return false;
}
/**
* SPARQL queries used within Fresnel must always return exactly one node
* set, meaning that only one variable is allowed in the query's SELECT clause.
*
* @see edu.mit.simile.fresnel.selection.ISelector#selectResources(Repository)
*/
public Iterator<Resource> selectResources(Repository in) throws InvalidResultSetException {
Vector<Resource> resources = new Vector<Resource>();
RepositoryConnection conn;
try {
conn = in.getConnection();
TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, this._SPARQL);
TupleQueryResult result = tupleQuery.evaluate();
String firstBindingName = result.getBindingNames().get(0);
while (result.hasNext()) {
Value uri = result.next().getBinding(firstBindingName).getValue();
if (uri instanceof URI) {
resources.add((Resource) uri);
}
}
result.close();
conn.close();
} catch (RepositoryException e) {
throw new InvalidResultSetException("Repository exception encountered selecting resources", e);
} catch (MalformedQueryException e) {
throw new InvalidResultSetException("Bad query encountered selecting resources using " + this._SPARQL, e);
} catch (QueryEvaluationException e) {
throw new InvalidResultSetException("Query evaluation exception encountered selecting resources using " + this._SPARQL, e);
}
return resources.iterator();
}
/**
* @see edu.mit.simile.fresnel.selection.ISelector#canSelectResources()
*/
public boolean canSelectResources() {
return true;
}
/**
* @see edu.mit.simile.fresnel.selection.ISelector#selectNodes(Repository)
*/
public Iterator<Value> selectNodes(Repository in) throws InvalidResultSetException {
Vector<Value> values = new Vector<Value>();
RepositoryConnection conn;
try {
conn = in.getConnection();
TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, this._SPARQL);
TupleQueryResult result = tupleQuery.evaluate();
String firstBindingName = result.getBindingNames().get(0);
while (result.hasNext()) {
Value uri = result.next().getBinding(firstBindingName).getValue();
if (uri instanceof URI) {
values.add(uri);
}
}
result.close();
conn.close();
} catch (RepositoryException e) {
throw new InvalidResultSetException("Repository exception encountered selecting nodes", e);
} catch (MalformedQueryException e) {
throw new InvalidResultSetException("Bad query encountered selecting nodes using " + this._SPARQL, e);
} catch (QueryEvaluationException e) {
throw new InvalidResultSetException("Query evaluation exception encountered selecting nodes using " + this._SPARQL, e);
}
return values.iterator();
}
/**
* @see edu.mit.simile.fresnel.selection.ISelector#canSelectNodes()
*/
public boolean canSelectNodes() {
return true;
}
/**
* This method will always return false.
*
* @see edu.mit.simile.fresnel.selection.ISelector#canSelect(Repository, Value)
*/
public boolean canSelect(Repository in, Value selected) {
return false;
}
}