/*
* 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.lang.reflect.Field;
import java.util.List;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.junit.Test;
import org.apache.jena.graph.Factory;
import org.apache.jena.graph.Graph;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Triple;
import org.apache.jena.reasoner.rulesys.FBRuleInfGraph;
import org.apache.jena.reasoner.rulesys.FBRuleReasoner;
import org.apache.jena.reasoner.rulesys.Rule;
import org.apache.jena.util.iterator.ExtendedIterator;
import org.apache.jena.vocabulary.RDF;
import org.apache.jena.vocabulary.RDFS;
public class TestLPBRuleEngine extends TestCase {
public static TestSuite suite() {
return new TestSuite(TestLPBRuleEngine.class, "TestLPBRuleEngine");
}
protected Node a = NodeFactory.createURI("a");
protected Node p = NodeFactory.createURI("p");
protected Node C1 = NodeFactory.createURI("C1");
protected Node C2 = NodeFactory.createURI("C2");
protected Node ty = RDF.Nodes.type;
public FBRuleReasoner createReasoner(List<Rule> rules) {
FBRuleReasoner reasoner = new FBRuleReasoner(rules);
reasoner.tablePredicate(RDFS.Nodes.subClassOf);
reasoner.tablePredicate(RDF.Nodes.type);
reasoner.tablePredicate(p);
return reasoner;
}
@Test
public void testTabledGoalsCacheHits() throws Exception {
Graph data = Factory.createGraphMem();
data.add(new Triple(a, ty, C1));
List<Rule> rules = Rule
.parseRules("[r1: (?x p ?t) <- (?x rdf:type C1), makeInstance(?x, p, C2, ?t)]"
+ "[r2: (?t rdf:type C2) <- (?x rdf:type C1), makeInstance(?x, p, C2, ?t)]");
FBRuleInfGraph infgraph = (FBRuleInfGraph) createReasoner(rules).bind(
data);
LPBRuleEngine engine = getEngineForGraph(infgraph);
assertEquals(0, engine.activeInterpreters.size());
assertEquals(0, engine.tabledGoals.size());
ExtendedIterator<Triple> it = infgraph.find(a, ty, C1);
while (it.hasNext()) {
it.next();
// FIXME: Why do I need to consume all from the iterator
// to avoid leaking activeInterpreters? Calling .close()
// below should have been enough.
}
it.close();
// how many were cached
assertEquals(1, engine.tabledGoals.size());
// and no leaks of activeInterpreters
assertEquals(0, engine.activeInterpreters.size());
// Now ask again:
it = infgraph.find(a, ty, C1);
while (it.hasNext()) {
it.next();
}
it.close();
// if it was a cache hit, no change here:
assertEquals(1, engine.tabledGoals.size());
assertEquals(0, engine.activeInterpreters.size());
}
@Test
public void testTabledGoalsLeak() throws Exception {
Graph data = Factory.createGraphMem();
data.add(new Triple(a, ty, C1));
List<Rule> rules = Rule
.parseRules("[r1: (?x p ?t) <- (?x rdf:type C1), makeInstance(?x, p, C2, ?t)]"
+ "[r2: (?t rdf:type C2) <- (?x rdf:type C1), makeInstance(?x, p, C2, ?t)]");
FBRuleInfGraph infgraph = (FBRuleInfGraph) createReasoner(rules).bind(
data);
LPBRuleEngine engine = getEngineForGraph(infgraph);
assertEquals(0, engine.activeInterpreters.size());
assertEquals(0, engine.tabledGoals.size());
ExtendedIterator<Triple> it = infgraph.find(a, ty, C1);
it.close();
// how many were cached
assertEquals(1, engine.tabledGoals.size());
// and no leaks of activeInterpreters
assertEquals(0, engine.activeInterpreters.size());
// Now ask again:
it = infgraph.find(a, ty, C1);
it.close();
// if it was a cache hit, no change here:
assertEquals(1, engine.tabledGoals.size());
assertEquals(0, engine.activeInterpreters.size());
//the cached generator should not have any consumingCP left
for(Generator generator : engine.tabledGoals.asMap().values()){
assertEquals(0, generator.consumingCPs.size());
}
}
@Test
public void testSaturateTabledGoals() throws Exception {
final int MAX = 1024;
// Set the cache size very small just for this test
System.setProperty("jena.rulesys.lp.max_cached_tabled_goals", "" + MAX);
try {
Graph data = Factory.createGraphMem();
data.add(new Triple(a, ty, C1));
List<Rule> rules = Rule
.parseRules("[r1: (?x p ?t) <- (?x rdf:type C1), makeInstance(?x, p, C2, ?t)]"
+ "[r2: (?t rdf:type C2) <- (?x rdf:type C1), makeInstance(?x, p, C2, ?t)]");
FBRuleInfGraph infgraph = (FBRuleInfGraph) createReasoner(rules)
.bind(data);
LPBRuleEngine engine = getEngineForGraph(infgraph);
assertEquals(0, engine.activeInterpreters.size());
assertEquals(0, engine.tabledGoals.size());
// JENA-901
// Let's ask about lots of unknown subjects
for (int i = 0; i < MAX * 128; i++) {
Node test = NodeFactory.createURI("test" + i);
ExtendedIterator<Triple> it = infgraph.find(test, ty, C2);
assertFalse(it.hasNext());
it.close();
}
// Let's see how many were cached
assertEquals(MAX, engine.tabledGoals.size());
// and no leaks of activeInterpreters (this will happen if we forget
// to call hasNext above)
assertEquals(0, engine.activeInterpreters.size());
} finally {
System.clearProperty("jena.rulesys.lp.max_cached_tabled_goals");
}
}
/**
* Use introspection to get to the LPBRuleEngine.
* <p>
* We are crossing package boundaries and therefore this test would always
* be in the wrong package for either FBRuleInfGraph or LPBRuleEngine.
* <p>
* <strong>This method should only be used for test purposes.</strong>
*
* @param infgraph
* @return
* @throws SecurityException
* @throws NoSuchFieldException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
private LPBRuleEngine getEngineForGraph(FBRuleInfGraph infgraph)
throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
Field bEngine = FBRuleInfGraph.class.getDeclaredField("bEngine");
bEngine.setAccessible(true);
LPBRuleEngine engine = (LPBRuleEngine) bEngine.get(infgraph);
return engine;
}
}