/* * 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.OneToManyMap ; /** * Indexes a collection of rule. The currently implementation is * a crude first version aimed at supporting the backchaining * interpreter. It only indexes on predicate. * <p> * The rules are normalized to only contain a single head element * by duplicating any multi headed rules. * </p> */ public class RuleStore { /** The set of rules indexed by head predicate */ protected OneToManyMap<Node, Rule> goalMap = new OneToManyMap<>(); /** The list of all rules in the store */ protected List<Rule> allRules; /** Index of the rules, used to block multiple entries */ protected Set<Rule> ruleIndex = new HashSet<>(); /** * Constructor. Create an empty rule store. */ public RuleStore() { allRules = new ArrayList<>(); } /** * Constructor. Stores and indexes a list of rules. */ public RuleStore(List<Rule> rules) { for ( Rule rule : rules ) { addRule( rule ); } allRules = rules; } /** * Add all the rules and from an existing rulestore into this one. */ public void addAll(RuleStore store) { for ( Rule rule : store.getAllRules() ) { addRule( rule ); } } /** * Add a single rule to the store. */ public void addRule(Rule rule) { addRemoveRule(rule, true); } /** * Remove a single rule from the store */ public void deleteRule(Rule rule) { addRemoveRule(rule, false); } /** * Add a single/remove a compound rule from the store. * @param rule the rule, may have multiple heads * @param isAdd true to add, false to remove */ private void addRemoveRule(Rule rule, boolean isAdd) { if (rule.headLength() != 1) { for (int j = 0; j < rule.headLength(); j++) { Rule newRule = new Rule(rule.getName(), new ClauseEntry[] {rule.getHeadElement(j)}, rule.getBody() ); newRule.setNumVars(rule.getNumVars()); doAddRemoveRule(newRule, isAdd); } } else { doAddRemoveRule(rule, isAdd); } } /** * Add/remove a single rule from the store. * @param rule the rule, single headed only * @param isAdd true to add, false to remove */ protected void doAddRemoveRule(Rule rule, boolean isAdd) { if (isAdd && ruleIndex.contains(rule)) return; if (isAdd) { ruleIndex.add(rule); if (allRules != null) allRules.add(rule); } else { ruleIndex.remove(rule); if (allRules != null) allRules.remove(rule); } Object headClause = rule.getHeadElement(0); if (headClause instanceof TriplePattern) { TriplePattern headpattern = (TriplePattern)headClause; Node predicate = headpattern.getPredicate(); if (predicate.isVariable()) { if (isAdd) { goalMap.put(Node.ANY, rule); } else { goalMap.remove(Node.ANY, rule); } } else { if (isAdd) { goalMap.put(predicate, rule); } else { goalMap.remove(predicate, rule); } } } } /** * Return a list of rules that match the given goal pattern * @param goal the goal being matched */ public List<Rule> rulesFor(TriplePattern goal) { List<Rule> rules = new ArrayList<>(); if (goal.getPredicate().isVariable()) { checkAll(goalMap.values().iterator(), goal, rules); } else { checkAll(goalMap.getAll(goal.getPredicate()), goal, rules); checkAll(goalMap.getAll(Node.ANY), goal, rules); } return rules; } /** * Return an ordered list of all registered rules. */ public List<Rule> getAllRules() { return allRules; } /** * Delete all the rules. */ public void deleteAllRules() { allRules.clear(); goalMap.clear(); ruleIndex.clear(); } /** * Helper method to extract all matching clauses from an * iterator over rules */ private void checkAll(Iterator<Rule> candidates, TriplePattern goal, List<Rule> matchingRules) { while (candidates.hasNext()) { Rule r = candidates.next(); if ( ((TriplePattern)r.getHeadElement(0)).compatibleWith(goal) ) { matchingRules.add(r); } } } }