package org.aksw.jena_sparql_api.views;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.aksw.jena_sparql_api.restriction.RestrictionManagerImpl;
import org.aksw.jena_sparql_api.utils.NodeTransformRenameMap;
import org.aksw.jena_sparql_api.utils.QuadPatternUtils;
import org.aksw.jena_sparql_api.utils.QuadUtils;
import org.aksw.sparqlify.database.Constraint;
import org.apache.jena.graph.Node;
import org.apache.jena.query.Query;
import org.apache.jena.sparql.algebra.Algebra;
import org.apache.jena.sparql.algebra.Op;
import org.apache.jena.sparql.algebra.OpVars;
import org.apache.jena.sparql.core.Quad;
import org.apache.jena.sparql.core.QuadPattern;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.engine.binding.BindingHashMap;
import org.apache.jena.sparql.engine.binding.BindingMap;
import org.apache.jena.sparql.expr.E_Equals;
import org.apache.jena.sparql.expr.Expr;
import org.apache.jena.sparql.expr.ExprList;
import org.apache.jena.sparql.graph.NodeTransform;
import org.apache.jena.sparql.graph.NodeTransformLib;
import org.apache.jena.sparql.modify.request.UpdateModify;
import org.apache.jena.sparql.syntax.Element;
import org.apache.jena.update.UpdateFactory;
import org.apache.jena.update.UpdateRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An SparqlView definition.
*
* Essentially a SPARQL construct query with constraints
*
*
* @author raven
*
*/
public class SparqlView
//implements View
implements IViewDef
{
private static final Logger logger = LoggerFactory.getLogger(SparqlView.class);
private String name;
//private RdfViewTemplate template;
private QuadPattern template;
private VarDefinition varDefinition;
private ExprList constraints;
private RestrictionManagerImpl restrictions;
public RestrictionManagerImpl getRestrictions() {
return restrictions;
}
public void setRestrictions(RestrictionManagerImpl restrictions) {
this.restrictions = restrictions;
}
private Op op; // The operation this view corresponds to
@Override
public Set<Var> getVarsMentioned()
{
Set<Var> result = new HashSet<Var>();
result.addAll(QuadPatternUtils.getVarsMentioned(template));
result.addAll(OpVars.mentionedVars(op));
return result;
}
public String getName()
{
return name;
}
/*
public RdfView getParent()
{
return parent;
}*/
/**
* Constructs a view definition
*
* syntax: [From graph] { ?s ?p ?o . Filter(?o = ...) . } with ?s = expr; ?p = ; select ...;
*
* Currently this is just some string hack
*
*
* @param pattern
*/
// public static SparqlView create(String str) {
// Map<String, String> defaultPrefixes = new HashMap<String, String>();
// defaultPrefixes.put("bif", "http://bif/");
// defaultPrefixes.put("rdf", RDF.getURI());
// defaultPrefixes.put("rdfs", RDFS.getURI());
// defaultPrefixes.put("geo", "http://ex.org/");
// defaultPrefixes.put("xsd", XSD.getURI());
// //defaultPrefixes.put("beef", "http://aksw.org/beef/");
// defaultPrefixes.put("spy", "http://aksw.org/sparqlify/");
//
// defaultPrefixes.put("wso", "http://aksw.org/wortschatz/ontology/");
// //defaultPrefixes.put("beef", "http://aksw.org/beef/");
// defaultPrefixes.put("rdf", RDF.getURI());
// defaultPrefixes.put("owl", OWL.getURI());
//
// return create("unnamed", str, defaultPrefixes);
// }
public static SparqlView create(String name, String viewDefStr) {
String str = viewDefStr.replaceAll("Construct", "Insert ");
System.out.println("Hack replacement: " + str);
UpdateRequest request = new UpdateRequest();
UpdateFactory.parse(request, str);
//request.getUpdates().
UpdateModify update = (UpdateModify)request.getOperations().get(0);
List<Quad> quads = update.getInsertQuads();
Element element = update.getWherePattern();
QuadPattern quadPattern = QuadPatternUtils.create(quads);
SparqlView result = create(name, quadPattern, element);
return result;
}
public static SparqlView create(String name, QuadPattern quadPattern, Element element) {
Op tmp = Algebra.compile(element);
Op op = Algebra.toQuadForm(tmp);
SparqlView result = create(name, quadPattern, op);
return result;
}
public static SparqlView create(String name, QuadPattern quadPattern, Op op) {
SparqlView result = new SparqlView(name, quadPattern, new ExprList(), new VarDefinition(), op);
return result;
}
public static SparqlView create(String name, Query query) {
if(!query.isConstructType()) {
throw new RuntimeException("Query must be a construct query");
}
Op tmp = Algebra.compile(query.getQueryPattern());
Op op = Algebra.toQuadForm(tmp);
QuadPattern quadPattern = QuadPatternUtils.toQuadPattern(Quad.defaultGraphNodeGenerated, query.getConstructTemplate().getBGP());
// QuadPattern quadPattern = new QuadPattern();
// for(Triple triple : query.getConstructTemplate().getTriples()) {
// quadPattern.add(new Quad(Quad.defaultGraphNodeGenerated, triple));
// }
SparqlView result = create(name, quadPattern, op);
//SparqlView result = new SparqlView(name, quadPattern, new ExprList(), new VarDefinition(), op);
return result;
}
/*
public static SparqlView create(ViewDefinition definition) {
return create(
definition.getName(),
definition.getViewTemplateDefinition().getConstructTemplate(),
definition.getFilters(),
definition.getViewTemplateDefinition().getVarBindings(),
definition.getConstraints(),
definition.getRelation()
);
}*/
/**
* Meh.... Didn't notice that template does not have support for graphs.
* Therefore need to change that...
*
* @param template
* @param filters
* @param bindings
* @param relation
* @return
*/
public static SparqlView create(String name, QuadPattern template, ExprList filters, List<Expr> bindings, List<Constraint> rawConstraints, Op op)
{
if(bindings == null) {
bindings = new ArrayList<Expr>();
}
/*
QuadPattern quadPattern = new QuadPattern();
for(Quad quad : template) {
//quadPattern.add(new Quad(Quad.defaultGraphNodeGenerated, triple));
}
*/
//Map<Node, Expr> bindingMap = new HashMap<Node, Expr>();
VarDefinition varDefinition = new VarDefinition();
for(Expr expr : bindings) {
if(!(expr instanceof E_Equals)) {
throw new RuntimeException("Binding expr must have form ?var = ... --- instead got: " + expr);
}
// Do macro expansion
// TODO Keep track of a non-macro-expanded version for human readability
// and easier debugging
Expr definition = expr.getFunction().getArg(2);
definition = SparqlSubstitute.substituteExpr(definition);
RestrictedExpr restExpr = new RestrictedExpr(definition);
Var var = expr.getFunction().getArg(1).asVar();
//bindingMap.put(var, definition);
varDefinition.getMap().put(var, restExpr);
}
//System.out.println("Binding = " + bindingMap);
if(rawConstraints == null) {
rawConstraints = Collections.emptyList();
}
ExprList constraints = new ExprList();
//logger.warn("Sanity checking of given patterns against derived ones and vice versa not implemented yet.");
logger.warn("Derivation of restrictions from expressions currently not implemented");
/*
// Derive regex patterns for all expressions
for(Entry<Node, Expr> entry : bindingMap.entrySet()) {
// If a constraint was given, skip deriving one.
if(!constraints.getVarPatternConstraints().containsKey(entry.getKey())) { //.getPattern((Var)entry.getKey());
RdfTermPattern derivedPattern = RdfTermPatternDerivation.deriveRegex(entry.getValue());
constraints.getVarPatternConstraints().put((Var)entry.getKey(), derivedPattern);
}
}
*/
return new SparqlView(name, template, constraints, varDefinition, op);
}
//
// public static SparqlView create(String name, String str, Map<String, String> defaultPrefixes) {
//
// PrefixMapping defaultPrefixMapping = new PrefixMappingImpl();
// defaultPrefixMapping.setNsPrefixes(defaultPrefixes);
//
// String parts1[] = str.split("\\swith\\s", 2);
// //String parts2[] = parts1[1].split("\\sselect\\s", 2);
// String parts2[] = parts1[1].split(";");
//
// String sqlStr = parts2[parts2.length - 1].trim();
//
// String queryStr = "Select * " + parts1[0];
// String bindingStrs[] = Arrays.copyOf(parts2, parts2.length - 1);
// //String sqlStr = "SELECT " + parts2[1];
//
//
// Query query = new Query();
// query.setPrefixMapping(defaultPrefixMapping);
// QueryFactory.parse(query, queryStr, null, Syntax.syntaxSPARQL);
// Op op = Algebra.compile(query);
// op = Algebra.toQuadForm(op);
//
// QuadPattern quadPattern = new QuadPattern();
//
// for(Quad quad : PatternUtils.collectQuads(op)) {
// quadPattern.add(quad);
// }
//
// //PatternUtils.
//
//
// //Map<Node, Expr> binding = new HashMap<Node, Expr>();
// VarDefinition varDefinition = new VarDefinition();
// for(String bindingStr : bindingStrs) {
// Expr expr = ExprUtils.parse(bindingStr, defaultPrefixMapping);
//
// if(!(expr instanceof E_Equals)) {
// throw new RuntimeException("Binding expr must have form ?var = ... --- instead got: " + bindingStr);
// }
//
// // Do macro expansion
// // TODO Keep track of a non-macro-expanded version for human readability
// // and easier debugging
//
// Expr definition = expr.getFunction().getArg(2);
// definition = SparqlSubstitute.substituteExpr(definition);
//
// RestrictedExpr restExpr = new RestrictedExpr(definition);
//
//
// Var var = expr.getFunction().getArg(1).asVar();
// //binding.put(var, definition);
// varDefinition.getMap().put(var, restExpr);
// }
//
//
// //System.out.println("Binding = " + binding);
//
// SqlNodeOld sqlExpr;
// if(sqlStr.startsWith("select")) {
// sqlExpr = new SqlQuery(null, sqlStr);
// } else {
// sqlExpr = new SqlTable(sqlStr);
// }
//
// ExprList constraints = FilterUtils.collectExprs(op, new ExprList());
// return new SparqlView(name, quadPattern, constraints, varDefinition, op);
// }
public SparqlView(String name, QuadPattern template, ExprList constraints, VarDefinition varDefinition, Op op)
{
super();
this.name = name;
this.template = template;
this.varDefinition = varDefinition;
this.constraints = constraints;
this.op = op;
}
/*
public SparqlView(String name, QuadPattern template, ExprList constraints, VarDefinition varDefinition,
Op sqlExpr)
{
super();
this.name = name;
this.template = template;
this.varDefinition = varDefinition;
//this.template = new RdfViewTemplate(quadPattern, binding);
this.constraints = constraints;
}
*/
@Deprecated
public QuadPattern getQuadPattern()
{
return template;
}
@Deprecated
public Map<Node, Expr> getBinding()
{
throw new RuntimeException("deprecated and removed");
//return template.getBinding();
//return null;
}
public Op getOp()
{
return op;
}
public ExprList getConstraints() {
return constraints;
}
@Override
public String toString()
{
return name;
//return "RdfView [template=" + template + ", filter=" + filter
// + ", sqlExpr=" + sqlNode + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SparqlView other = (SparqlView) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public QuadPattern getTemplate() {
return template;
}
private RestrictionManagerImpl varRestrictions = new RestrictionManagerImpl();
@Override
public RestrictionManagerImpl getVarRestrictions() {
return varRestrictions;
//throw new RuntimeException("Not implemented");
}
@Override
public VarDefinition getVarDefinition() {
return varDefinition;
}
@Deprecated
public SparqlView copySubstitute(Map<Node, Node> renamer) {
throw new RuntimeException("not there anymore");
}
@Override
public SparqlView copyRenameVars(Map<Var, Var> oldToNew) {
Map<Node, Node> map = new HashMap<Node, Node>();
for(Entry<Var, Var> entry : oldToNew.entrySet()) {
map.put(entry.getKey(), entry.getValue());
}
ExprList tmpFilter = new ExprList();
NodeTransform rename = new NodeTransformRenameMap(map);
for(Expr expr : constraints) {
tmpFilter.add(expr.applyNodeTransform(rename));
}
BindingMap bindingMap = new BindingHashMap();
for(Entry<Node, Node> entry : map.entrySet()) {
bindingMap.add((Var)entry.getKey(), entry.getValue());
}
NodeTransformRenameMap renamer = new NodeTransformRenameMap(map);
Op renamedOp = NodeTransformLib.transform(renamer, op);
SparqlView result = new SparqlView(name, QuadUtils.copySubstitute(template, map),
constraints.copySubstitute(bindingMap),
null, // FIXME: varDefinition.copyRenameVars(map),
renamedOp);
return result; }
}