/*
* 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 org.apache.jena.graph.* ;
import org.apache.jena.reasoner.* ;
import org.apache.jena.reasoner.rulesys.* ;
import org.apache.jena.util.iterator.ClosableIterator ;
/**
* An implementation of the generic RuleContext for use in the RETE implementation.
* The RuleContext is used to supply context information to the builtin operations.
*/
public class RETERuleContext implements RuleContext {
/** The binding environment which represents the state of the current rule execution. */
protected BindingEnvironment env;
/** The rule current being executed. */
protected Rule rule;
/** The enclosing inference graph. */
protected ForwardRuleInfGraphI graph;
/** The RETE engine associated with the inference graph */
protected RETEEngine engine;
/**
* Constructor.
* @param graph the inference graph which owns this context.
*/
public RETERuleContext(ForwardRuleInfGraphI graph, RETEEngine engine) {
this.graph = graph;
this.engine = engine;
}
/**
* Returns the current variable binding environment for the current rule.
* @return BindingEnvironment
*/
@Override
public BindingEnvironment getEnv() {
return env;
}
/**
* Returns the graph.
* @return InfGraph
*/
@Override
public InfGraph getGraph() {
return graph;
}
/**
* Returns the RETE engine associated with this context.
*/
public RETEEngine getEngine() {
return engine;
}
/**
* 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;
}
/**
* Sets the current binding environment for this context.
* @param env the binding environment so far
*/
public void setEnv(BindingEnvironment env) {
this.env = env;
}
/**
* 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) {
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);
}
/**
* 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) {
graph.getRawGraph().delete(t);
engine.deleteTriple(t, true);
}
/**
* Assert a new triple in the deduction graph, triggering any consequent processing as appropriate.
*/
@Override
public void add(Triple t) {
engine.addTriple(t, true);
}
/**
* Check whether the rule should fire in this context.
*/
public boolean shouldFire(boolean allowUnsafe) {
// Check any non-pattern clauses
for (int i = 0; i < rule.bodyLength(); i++) {
Object clause = rule.getBodyElement(i);
if (clause instanceof Functor) {
// Fire a built in
if (allowUnsafe) {
if (!((Functor)clause).evalAsBodyClause(this)) {
// Failed guard so just discard and return
return false;
}
} else {
// Don't re-run side-effectful clause on a re-run
if (!((Functor)clause).safeEvalAsBodyClause(this)) {
// Failed guard so just discard and return
return false;
}
}
}
}
return true;
}
/**
* Check if a rule from the conflict set is still OK to fire.
* Just checks the non-monotonic guards such as noValue.
*/
public boolean shouldStillFire() {
// Check any non-pattern clauses
for (int i = 0; i < rule.bodyLength(); i++) {
Object clause = rule.getBodyElement(i);
if (clause instanceof Functor) {
Builtin builtin = ((Functor)clause).getImplementor();
if (builtin != null && !builtin.isMonotonic()) {
if (!((Functor)clause).evalAsBodyClause(this)) {
return false;
}
}
}
}
return true;
}
}