/*
* 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.reasoner.rulesys.impl;
import java.util.*;
import org.apache.jena.graph.* ;
import org.apache.jena.reasoner.* ;
import org.apache.jena.reasoner.rulesys.* ;
import org.apache.jena.util.PrintUtil ;
import org.apache.jena.util.iterator.ClosableIterator ;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An implementation of the generic RuleContext interface used by
* the basic forward (BF) rule engine. This provides additional
* methods specific to the functioning of that engine.
*/
public class BFRuleContext implements RuleContext {
/** The binding environment which represents the state of the current rule execution. */
protected BindingStack env;
/** The rule current being executed. */
protected Rule rule;
/** The enclosing inference graph. */
protected ForwardRuleInfGraphI graph;
/** A stack of triples which have been added to the graph but haven't yet been processed. */
protected List<Triple> stack;
/** A temporary list of Triples which will be added to the stack and triples at the end of a rule scan */
protected List<Triple> pending;
/** A temporary list of Triples which will be removed from the graph at the end of a rule scan */
protected List<Triple> deletesPending = new ArrayList<>();
/** A searchable index into the pending triples */
protected Graph pendingCache;
protected static Logger logger = LoggerFactory.getLogger(BFRuleContext.class);
/**
* Constructor.
* @param graph the inference graph which owns this context.
*/
public BFRuleContext(ForwardRuleInfGraphI graph) {
this.graph = graph;
env = new BindingStack();
stack = new ArrayList<>();
pending = new ArrayList<>();
pendingCache = Factory.createGraphMem();
}
/**
* Returns the current variable binding environment for the current rule.
* @return BindingEnvironment
*/
@Override
public BindingEnvironment getEnv() {
return env;
}
/**
* Variant of the generic getEnv interface specific to the basic
* forward rule system.
* Returns the current variable binding environment for the current rule.
* @return BindingStack
*/
public BindingStack getEnvStack() {
return env;
}
/**
* Returns the graph.
* @return InfGraph
*/
@Override
public InfGraph getGraph() {
return graph;
}
/**
* Returns the rule.
* @return Rule
*/
@Override
public Rule getRule() {
return rule;
}
/**
* Sets the rule.
* @param rule The rule to set
*/
@Override
public void setRule(Rule rule) {
this.rule = rule;
}
/**
* Add a triple to the stack of triples to waiting to be processed by the rule engine.
*/
public void addTriple(Triple t) {
if (graph.shouldTrace()) {
if (rule != null) {
logger.debug("Adding to stack (" + rule.toShortString() + "): " + PrintUtil.print(t));
} else {
logger.debug("Adding to stack : " + PrintUtil.print(t));
}
}
stack.add(t);
}
/**
* Add a triple to a temporary "pending" store, ready to be added to added to the
* deductions graph and the processing stack later.
* <p>This is needed to prevent concurrrent modification exceptions which searching
* the deductions for matches to a given rule.
*/
@Override
public void add(Triple t) {
if (graph.shouldTrace()) {
if (rule != null) {
logger.debug("Adding to pending (" + rule.toShortString() + "): " + PrintUtil.print(t));
} else {
logger.debug("Adding to pending : " + PrintUtil.print(t));
}
}
pending.add(t);
//pendingCache.add(t);
}
/**
* Take all the pending triples and add them to both the given graph and
* to the processing stack.
*/
public void flushPending() {
for (Iterator<Triple> i = pending.iterator(); i.hasNext(); ) {
Triple t = i.next();
stack.add(t);
graph.addDeduction(t);
i.remove();
// pendingCache.delete(t);
}
pending.clear();
// Flush out pending removes as well
for ( Triple t : deletesPending )
{
graph.delete( t );
}
deletesPending.clear();
}
/**
* Return true if the triple is already in either the graph or the stack.
* I.e. it has already been deduced.
*/
@Override
public boolean contains(Triple t) {
// Can't use stackCache.contains because that does not do semantic equality
return contains(t.getSubject(), t.getPredicate(), t.getObject());
}
/**
* Return true if the triple pattern is already in either the graph or the stack.
* I.e. it has already been deduced.
*/
@Override
public boolean contains(Node s, Node p, Node o) {
// Can't use stackCache.contains because that does not do semantic equality
ClosableIterator<Triple> it = find(s, p, o);
boolean result = it.hasNext();
it.close();
return result;
}
/**
* In some formulations the context includes deductions that are not yet
* visible to the underlying graph but need to be checked for.
* However, currently this calls the graph find directly.
*/
@Override
public ClosableIterator<Triple> find(Node s, Node p, Node o) {
//return graph.find(s, p, o).andThen(pendingCache.find(s, p, o));
return graph.findDataMatches(s, p, o);
}
/**
* Return the next triple to be added to the graph, removing it from
* the stack.
* @return the Triple or null if there are no more
*/
public Triple getNextTriple() {
if (stack.size() > 0) {
Triple t = stack.remove(stack.size() - 1);
return t;
} else {
return null;
}
}
/**
* Reset the binding environemnt back to empty.
* @param newSize the number of variables needed for processing the new rule
*/
public void resetEnv(int newSize) {
env.reset(newSize);
}
/**
* Assert a new triple in the deduction graph, bypassing any processing machinery.
*/
@Override
public void silentAdd(Triple t) {
((SilentAddI)graph).silentAdd(t);
}
/**
* Remove a triple from the deduction graph (and the original graph if relevant).
*/
@Override
public void remove(Triple t) {
deletesPending.add(t);
// graph.delete(t);
}
}