package org.openanzo.datasource.nodecentric.query.predicates;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.openanzo.glitter.exception.FunctionalPredicateInvocationException;
import org.openanzo.glitter.exception.GlitterException;
import org.openanzo.glitter.query.FunctionalPredicate;
import org.openanzo.glitter.query.NodeCostModel;
import org.openanzo.glitter.query.PatternSolution;
import org.openanzo.glitter.query.QueryInformation;
import org.openanzo.glitter.query.SolutionSet;
import org.openanzo.rdf.Bindable;
import org.openanzo.rdf.TriplePattern;
import org.openanzo.rdf.URI;
import org.openanzo.rdf.Value;
import org.openanzo.rdf.Variable;
/**
* {@link ListMemberPredicate} is a {@link FunctionalPredicate} that implements the predicate <tt>http://www.jena.hpl.hp.com/ARQ/list#member</tt>. See the <a
* href="http://www.openanzo.org/projects/openanzo/wiki/QueryingLists">QueryingLists</a> Open Anzo wiki page.
*
* @author lee <lee@cambridgesemantics.com>
*
*/
public class ListMemberPredicate implements FunctionalPredicate {
private TriplePattern tp = null;
public boolean canBindGraphVariables() {
return true;
}
public SolutionSet generateSolutions(URI namedGraph, Variable namedGraphVariable, SolutionSet bindingConstraints) throws GlitterException {
try {
Map<Value, List<Value>> lists = new HashMap<Value, List<Value>>();
if (tp.getSubject() instanceof Bindable) {
for (PatternSolution ps : bindingConstraints) {
lists.put(ps.getBinding((Bindable) tp.getSubject()), new ArrayList<Value>());
}
} else {
lists.put((Value) tp.getSubject(), new ArrayList<Value>());
}
// this maps Anzo node IDs into the RDF term (IRI or blank node) that represents the head of the
// list
//Map<Long, RDFTerm> listNode2List = new HashMap<Long, RDFTerm>();
/**
*
* We recursively translate ?list list:member ?member into ?list rdf:first ?member ?list rdf:rest ?next followed by ?list := ?next
*
* TODO - this isn't quite so simple: we can't recurse at the SPARQL level on bnodes, since we can't identify specific bnodes in a triple pattern
* (no told bnodes). However, we can do this at the Anzo level by simply reusing the same blank node's ID, so we need a slightly lower level
* interaction with the database, whereby we can pass in the *ID* of next.
*/
/*
Variable member = Variable.createVariable("member"), next = Variable.createVariable("next");
BGP bgp = new BGP();
TriplePattern rdffirst = new TriplePattern(tp.getSubject(), new IRIReference(RDF.FIRST), member), rdfrest = new TriplePattern(tp.getSubject(), new IRIReference(RDF.REST), next);
bgp.addTriplePattern(new TriplePatternNode(rdffirst));
bgp.addTriplePattern(new TriplePatternNode(rdfrest));
ServerBGPQuery q = new ServerBGPQuery(this.context, qi, this.lastTransactionTime);
q.setThisNode(bgp);
if (namedGraph != null)
q.setNamedGraph(namedGraph);
if (namedGraphVariable != null)
q.setGraphVariable(namedGraphVariable);
q.addTriplePattern(rdffirst);
q.addTriplePattern(rdfrest);
String sql = q.getSQL(null);
Statement statement = this.context.getConnection().createStatement();
ResultSet rs = statement.executeQuery(sql);
SolutionList solutions = new SolutionList();
//this.sg.addBindings(q, bgp, rs, solutions, bindableColumns);
for (PatternSolution solution : solutions) {
solution.getBinding(namedGraphVariable);
}
return null;
} catch (SQLException e) {
return null;
}
*/} finally {
}
return null;
}
/**
* Relatively expensive cost since it involves recursive queries.
*/
public double getCost(NodeCostModel costModel) {
return 100;
}
public TriplePattern getFunctionalTriplePattern() {
return this.tp;
}
/**
* Don't handle any other triple patterns besides the functional triple pattern.
*/
public boolean handlesTriplePattern(TriplePattern pattern) throws FunctionalPredicateInvocationException {
return false;
}
public void initialize(QueryInformation qi) {
}
public void setFunctionalTriplePattern(TriplePattern pattern) throws FunctionalPredicateInvocationException {
this.tp = pattern;
}
public boolean usesDataFromGraphs() {
return true;
}
}