| /* |
| * 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.engine.iterator; |
| |
| import static org.apache.jena.graph.Node_Triple.triple; |
| |
| import org.apache.jena.atlas.lib.Pair; |
| import org.apache.jena.graph.Node; |
| import org.apache.jena.graph.Triple; |
| import org.apache.jena.sparql.ARQConstants; |
| import org.apache.jena.sparql.core.Var; |
| import org.apache.jena.sparql.core.VarAlloc; |
| import org.apache.jena.sparql.engine.ExecutionContext; |
| import org.apache.jena.sparql.engine.QueryIterator; |
| import org.apache.jena.sparql.util.Context; |
| |
| /** |
| * Solver library for RDF*. |
| * <p> |
| * There are two entry points. |
| * <p> |
| * Function {@link #rdfStarTriple} for matching a single triple pattern in a basic |
| * graph pattern that may involve RDF* terms. |
| * <p> |
| * Function {@link #matchTripleStar} for matches a triple term and assigning the |
| * triple matched to a variable. It is used within {@link #rdfStarTriple} for nested |
| * triple term and a temporary allocated variable as well can for |
| * {@code FIND(<<...>> AS ?t)}. |
| */ |
| public class RX { |
| |
| /** |
| * Match a single triple pattern that may involve RDF* terms. |
| * This is the top level function for matching triples. |
| * |
| * The function {@link #matchTripleStar} matches a triple term and assigns the triple matched to a variable. |
| * It is used within {@link #rdfStarTriple} for nested triple term and a temporary allocated variable |
| * as well can for {@code FIND(<<...>> AS ?t)}. |
| * |
| * @implNote |
| * Without RDF*, this would be a plain call of {@link #matchData} which is simply: |
| * <pre> |
| * new QueryIterTriplePattern(chain, triple, execCxt)} |
| * </pre> |
| */ |
| public static QueryIterator rdfStarTriple(QueryIterator chain, Triple triple, ExecutionContext execCxt) { |
| // Should all work without this trap for plain RDF. |
| if ( ! tripleHasNodeTriple(triple) ) |
| // No RDF* : direct to data. |
| return matchData(chain, triple, execCxt); |
| return rdfStarTripleSub(chain, triple, execCxt); |
| } |
| |
| private static VarAlloc varAlloc(ExecutionContext execCxt) { |
| Context context = execCxt.getContext(); |
| VarAlloc varAlloc = VarAlloc.get(context, ARQConstants.sysVarAllocRDFStar); |
| if ( varAlloc == null ) { |
| varAlloc = new VarAlloc(ARQConstants.allocVarTripleTerm); |
| context.set(ARQConstants.sysVarAllocRDFStar, varAlloc); |
| } |
| return varAlloc; |
| } |
| |
| /** |
| * Insert the stages necessary for a triple with triple pattern term inside it. |
| * If the triple pattern has a triple term, possibly with variables, introduce |
| * an iterator to solve for that, assign the matching triple term to a hidden |
| * variable, and put allocated variable in to main triple pattern. Do for subject |
| * and object positions, and also any nested triple pattern terms. |
| */ |
| private static QueryIterator rdfStarTripleSub(QueryIterator chain, Triple triple, ExecutionContext execCxt) { |
| Pair<QueryIterator, Triple> pair = preprocessForTripleTerms(chain, triple, execCxt); |
| QueryIterator chain2 = matchData(pair.getLeft(), pair.getRight(), execCxt); |
| return chain2; |
| } |
| |
| /** |
| * Match a triple pattern (which may have nested triple terms in it). |
| * Any matched triples are added as triple terms bound to the supplied variable. |
| */ |
| public static QueryIterator matchTripleStar(QueryIterator chain, Var var, Triple triple, ExecutionContext execCxt) { |
| if ( tripleHasNodeTriple(triple) ) { |
| Pair<QueryIterator, Triple> pair = preprocessForTripleTerms(chain, triple, execCxt); |
| chain = pair.getLeft(); |
| triple = pair.getRight(); |
| } |
| // Match to data and assign to var in each binding, based on the triple pattern grounded by the match. |
| QueryIterator qIter = bindTripleTerm(chain, var, triple, execCxt); |
| return qIter; |
| } |
| |
| /** |
| * Process a triple for triple terms. |
| * <p> |
| * This creates additional matchers for triple terms in the pattern triple recursively. |
| */ |
| private static Pair<QueryIterator, Triple> preprocessForTripleTerms(QueryIterator chain, Triple patternTriple, ExecutionContext execCxt) { |
| Node s = patternTriple.getSubject(); |
| Node p = patternTriple.getPredicate(); |
| Node o = patternTriple.getObject(); |
| Node s1 = null; |
| Node o1 = null; |
| |
| // Recurse. |
| if ( s.isNodeTriple() && ! s.isConcrete() ) { |
| Triple t2 = triple(s); |
| Var var = varAlloc(execCxt).allocVar(); |
| Triple tripleTerm = Triple.create(t2.getSubject(), t2.getPredicate(), t2.getObject()); |
| chain = matchTripleStar(chain, var, tripleTerm, execCxt); |
| s1 = var; |
| } |
| if ( o.isNodeTriple() && ! o.isConcrete() ) { |
| Triple t2 = triple(o); |
| Var var = varAlloc(execCxt).allocVar(); |
| Triple tripleTerm = Triple.create(t2.getSubject(), t2.getPredicate(), t2.getObject()); |
| chain = matchTripleStar(chain, var, tripleTerm, execCxt); |
| o1 = var; |
| } |
| |
| // Because of the test in rdfStarTriple, |
| // This code only happens when there is a a triple term. |
| |
| // No triple term in this triple. |
| if ( s1 == null && o1 == null ) |
| return Pair.create(chain, patternTriple); |
| |
| // Change. Replace original. |
| if ( s1 == null ) |
| s1 = s ; |
| if ( o1 == null ) |
| o1 = o ; |
| Triple triple1 = Triple.create(s1, p, o1); |
| return Pair.create(chain, triple1); |
| } |
| |
| /** |
| * Add a binding to each row with triple grounded by the current row. |
| * If the triple isn't concrete, then just return the row as-is. |
| */ |
| private static QueryIterator bindTripleTerm(QueryIterator chain, Var var, Triple pattern, ExecutionContext execCxt) { |
| QueryIterator qIter = matchData(chain, pattern, execCxt); |
| QueryIterator qIter2 = new QueryIterAddTripleTerm(qIter, var, pattern, execCxt); |
| return qIter2; |
| } |
| |
| /** |
| * Match the graph with a triple pattern. |
| * This is the accessor to the graph. |
| * It assumes any triple terms have been dealt with. |
| */ |
| private static QueryIterator matchData(QueryIterator chain, Triple pattern, ExecutionContext execCxt) { |
| return new QueryIterTriplePattern(chain, pattern, execCxt); |
| } |
| |
| /** |
| * Test whether a triple has an triple term as one of its components. |
| */ |
| private static boolean tripleHasNodeTriple(Triple triple) { |
| return triple.getSubject().isNodeTriple() |
| /*|| triple.getPredicate().isNodeTriple()*/ |
| || triple.getObject().isNodeTriple(); |
| } |
| } |
| |