blob: b82753dd1241711edeeef9c381649fb485938e6c [file] [log] [blame]
/*
* 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 org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.Triple ;
import org.apache.jena.sparql.ARQInternalErrorException ;
import org.apache.jena.sparql.core.Var ;
import org.apache.jena.sparql.engine.ExecutionContext ;
import org.apache.jena.sparql.engine.QueryIterator ;
import org.apache.jena.sparql.engine.binding.Binding ;
import org.apache.jena.sparql.engine.binding.BindingFactory ;
import org.apache.jena.sparql.engine.binding.BindingMap ;
import org.apache.jena.sparql.serializer.SerializationContext;
import org.apache.jena.util.iterator.ClosableIterator ;
import org.apache.jena.util.iterator.NiceIterator ;
/** Match a single triple pattern */
public class QueryIterTriplePattern extends QueryIterRepeatApply
{
private final Triple pattern ;
public QueryIterTriplePattern( QueryIterator input,
Triple pattern ,
ExecutionContext cxt)
{
super(input, cxt) ;
this.pattern = pattern ;
}
@Override
protected QueryIterator nextStage(Binding binding)
{
return new TripleMapper(binding, pattern, getExecContext()) ;
}
@Override
protected void details(IndentedWriter out, SerializationContext sCxt) {
out.print("QueryIterTriplePattern: " + pattern);
}
static int countMapper = 0 ;
static class TripleMapper extends QueryIter
{
private Node s ;
private Node p ;
private Node o ;
private Binding binding ;
private ClosableIterator<Triple> graphIter ;
private Binding slot = null ;
private boolean finished = false ;
private volatile boolean cancelled = false ;
TripleMapper(Binding binding, Triple pattern, ExecutionContext cxt)
{
super(cxt) ;
this.s = substitute(pattern.getSubject(), binding) ;
this.p = substitute(pattern.getPredicate(), binding) ;
this.o = substitute(pattern.getObject(), binding) ;
this.binding = binding ;
Node s2 = tripleNode(s) ;
Node p2 = tripleNode(p) ;
Node o2 = tripleNode(o) ;
Graph graph = cxt.getActiveGraph() ;
this.graphIter = graph.find(s2, p2, o2) ;
}
private static Node tripleNode(Node node)
{
if ( node.isVariable() )
return Node.ANY ;
return node ;
}
private static Node substitute(Node node, Binding binding)
{
if ( Var.isVar(node) )
{
Node x = binding.get(Var.alloc(node)) ;
if ( x != null )
return x ;
}
return node ;
}
private Binding mapper(Triple r)
{
BindingMap results = BindingFactory.create(binding) ;
if ( ! insert(s, r.getSubject(), results) )
return null ;
if ( ! insert(p, r.getPredicate(), results) )
return null ;
if ( ! insert(o, r.getObject(), results) )
return null ;
return results ;
}
private static boolean insert(Node inputNode, Node outputNode, BindingMap results)
{
if ( ! Var.isVar(inputNode) )
return true ;
Var v = Var.alloc(inputNode) ;
Node x = results.get(v) ;
if ( x != null )
return outputNode.equals(x) ;
results.add(v, outputNode) ;
return true ;
}
@Override
protected boolean hasNextBinding()
{
if ( finished ) return false ;
if ( slot != null ) return true ;
if ( cancelled )
{
graphIter.close() ;
finished = true ;
return false ;
}
while(graphIter.hasNext() && slot == null )
{
Triple t = graphIter.next() ;
slot = mapper(t) ;
}
if ( slot == null )
finished = true ;
return slot != null ;
}
@Override
protected Binding moveToNextBinding()
{
if ( ! hasNextBinding() )
throw new ARQInternalErrorException() ;
Binding r = slot ;
slot = null ;
return r ;
}
@Override
protected void closeIterator()
{
if ( graphIter != null )
NiceIterator.close(graphIter) ;
graphIter = null ;
}
@Override
protected void requestCancel()
{
// The QueryIteratorBase machinary will do the real work.
cancelled = true ;
}
}
}