/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jena.sparql.algebra; import java.util.ArrayDeque ; import java.util.Collection ; import java.util.Deque ; import org.apache.jena.graph.Node ; import org.apache.jena.sparql.ARQConstants ; import org.apache.jena.sparql.algebra.op.* ; import org.apache.jena.sparql.core.Quad ; import org.apache.jena.sparql.core.Var ; import org.apache.jena.sparql.core.VarAlloc ; /** * Helper class for converting an algebra expression into a quad form * */ public class AlgebraQuad { // Transform to a quad form: // + BGPs go to quad patterns // + Drop (previous) OpGraph // + Paths (complex - simple ones are flatten elsewhere) go to (graph (path ...)) [later: quad paths] // Done as a before/after pair to run the stack of graph nodes for rewrite. // Need to be careful of use of a variable in GRAPH ?g { .. } and then use ?g inside the pattern. private AlgebraQuad() { } public static Op quadize(Op op) { final Deque<QuadSlot> stack = new ArrayDeque<>() ; QuadSlot qSlot = new QuadSlot(Quad.defaultGraphNodeGenerated, Quad.defaultGraphNodeGenerated) ; stack.push(qSlot) ; // Starting condition OpVisitor before = new Pusher(stack) ; OpVisitor after = new Popper(stack) ; TransformQuadGraph qg = new TransformQuadGraph(stack, before, after) ; return Transformer.transformSkipService(qg, null, op, before, after) ; } /** This is the record of the transformation. * The rewriteGraphName is the node to put in the graph slot of the quad. * The actualGraphName is the node used in SPARQL. * If they are the same (by ==), the quadrewrite is OK as is. * If they are different (and that means they are variables) * an assign is done after the execution of the graph pattern block. */ static class QuadSlot { // No longer needed (rewriting done elsewhere). // Remove and use a stack of Nodes. final Node actualGraphName ; final Node rewriteGraphName ; QuadSlot(Node actualGraphName, Node rewriteGraphName) { this.actualGraphName = actualGraphName ; this.rewriteGraphName = rewriteGraphName ; } @Override public String toString() { return "actualGraphName="+actualGraphName+" rewriteGraphName="+rewriteGraphName ; } } private static class Pusher extends OpVisitorBase { Deque<QuadSlot> stack ; VarAlloc varAlloc = new VarAlloc(ARQConstants.allocVarQuad) ; Pusher(Deque<QuadSlot> stack) { this.stack = stack ; } @Override public void visit(OpGraph opGraph) { // Name in SPARQL Node gn = opGraph.getNode() ; // Name in rewrite Node gnQuad = gn ; if ( Var.isVar(gn) ) { Collection<Var> vars = OpVars.mentionedVars(opGraph.getSubOp()) ; if ( vars.contains(gn) ) gnQuad = varAlloc.allocVar() ; } //System.out.println("Pusher: "+gn) ; stack.push(new QuadSlot(gn, gnQuad)) ; } } private static class Popper extends OpVisitorBase { Deque<QuadSlot> stack ; Popper(Deque<QuadSlot> stack) { this.stack = stack ; } @Override public void visit(OpGraph opGraph) { // The final work is done in the main vistor, // which is called after the subnode has been // rewritten. QuadSlot qs = stack.pop() ; //System.out.println("Popper: "+qs.rewriteGraphName) ; } } }