package org.aksw.jena_sparql_api.algebra.transform; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import org.aksw.jena_sparql_api.utils.Generator; import org.aksw.jena_sparql_api.utils.VarGeneratorBlacklist; import org.apache.jena.graph.Node; import org.apache.jena.graph.Triple; import org.apache.jena.sparql.algebra.Op; import org.apache.jena.sparql.algebra.OpVars; import org.apache.jena.sparql.algebra.Transform; import org.apache.jena.sparql.algebra.TransformCopy; import org.apache.jena.sparql.algebra.Transformer; import org.apache.jena.sparql.algebra.op.OpFilter; import org.apache.jena.sparql.algebra.op.OpProject; import org.apache.jena.sparql.algebra.op.OpQuadPattern; import org.apache.jena.sparql.core.BasicPattern; import org.apache.jena.sparql.core.Quad; import org.apache.jena.sparql.core.Var; 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.expr.ExprVar; import org.apache.jena.sparql.expr.NodeValue; public class TransformReplaceConstants extends TransformCopy { protected Generator<Var> generator; protected boolean omitDefaultGraphFilter; public TransformReplaceConstants(Generator<Var> generator, boolean omitDefaultGraphFilter) { this.generator = generator; this.omitDefaultGraphFilter = omitDefaultGraphFilter; } public static Triple listToTriple(List<Node> nodes) { return new Triple(nodes.get(0), nodes.get(1), nodes.get(2)); } public static List<Node> tripleToList(Triple triple) { List<Node> result = new ArrayList<Node>(); result.add(triple.getSubject()); result.add(triple.getPredicate()); result.add(triple.getObject()); return result; } public static Op transform(Op op) { Collection<Var> mentionedVars = OpVars.mentionedVars(op); Set<Var> oldVisibleVars = OpVars.visibleVars(op); Generator<Var> gen = VarGeneratorBlacklist.create("v", mentionedVars); Transform transform = new TransformReplaceConstants(gen, false); Op result = Transformer.transform(transform, op); // Ensure the correct projection Set<Var> newVisibleVars = OpVars.visibleVars(op); if(!oldVisibleVars.equals(newVisibleVars)) { result = new OpProject(result, new ArrayList<>(oldVisibleVars)); } return result; } public static Node transform(Node node, boolean isGraphNode, Generator<Var> generator, ExprList filters, boolean omitDefaultGraphFilter) { if(node.isConcrete()) { Var var = generator.next(); // Use of the constant Quad.defaultGraphNodeGenerated in the graph position results in a free variable. if(!omitDefaultGraphFilter || !(isGraphNode && node.equals(Quad.defaultGraphNodeGenerated))) { Expr condition = new E_Equals(new ExprVar(var), NodeValue.makeNode(node)); filters.add(condition); } return var; } return node; } public Op transform(OpQuadPattern op) { //List<Var> vars = new ArrayList<>(OpVars.visibleVars(op)); ExprList filters = new ExprList(); BasicPattern triples = new BasicPattern(); boolean retainDefaultGraphNode = true; Node graphNode = retainDefaultGraphNode && op.getGraphNode().equals(Quad.defaultGraphNodeGenerated) ? Quad.defaultGraphNodeGenerated : transform(op.getGraphNode(), true, generator, filters, omitDefaultGraphFilter); // TODO Mapping of nodes might be doable with jena transform List<Node> nodes = new ArrayList<Node>(); for(Triple triple : op.getBasicPattern().getList()) { for(Node node : tripleToList(triple)) { Node n = transform(node, false, generator, filters, omitDefaultGraphFilter); nodes.add(n); } Triple t = listToTriple(nodes); triples.add(t); nodes.clear(); } Op result = new OpQuadPattern(graphNode, triples); if(!filters.isEmpty()) { result = OpFilter.filter(filters, result); } // Note: We need to add a projection here, so we do not suddely yield more variables than // in the original pattern - otherwise, we could break e.g. SELECT * { ... } queries. // result = new OpProject(result, vars); return result; } // // public static Op _replace(OpQuadBlock op) { // throw new RuntimeException("Not implemented yet"); //// ExprList filters = new ExprList(); //// //// //// //BasicPattern triples = new BasicPattern(); //// QuadPattern quadPattern = new QuadPattern(); //// //// //Node rawGraphNode = op.getGraphNode(); //// ////// Node commonGraphNode = null; ////// if(rawGraphNode.isConcrete()) { ////// // If the graph node is a concrete value - except for the default graph, ////// // replace it with a variable that is constrained to that value ////// if(!rawGraphNode.equals(Quad.defaultGraphNodeGenerated)) { ////// commonGraphNode = transform(rawGraphNode, false, generator, filters); ////// } ////// } ////// else { ////// // If the graph node is a variable, use it. ////// commonGraphNode = rawGraphNode; ////// } //// //// //// List<Node> nodes = new ArrayList<Node>(4); //// for(Quad quad : op.getPattern()) { //// //// Node graphNode; //// if(commonGraphNode != null) { //// graphNode = commonGraphNode; //// } else { //// graphNode = Var.alloc(generator.next()); //// } //// nodes.add(graphNode); //// //// //// for(Node node : tripleToList(triple)) { //// //// Node n = transform(node, generator, filters); //// nodes.add(n); //// } //// //// //Triple t = listToTriple(nodes); //// //// //triples.add(t); //// Quad q = QuadUtils.listToQuad(nodes); //// quadPattern.add(q); //// nodes.clear(); //// } //// //// Op result = new OpQuadBlock(quadPattern); //// //// if(!filters.isEmpty()) { //// result = OpFilter.filter(filters, result); //// } //// //// return result; // } }