001: /******************************************************************
002: * File: FBRuleInfGraph.java
003: * Created by: Dave Reynolds
004: * Created on: 28-May-2003
005: *
006: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: FBRuleInfGraph.java,v 1.67 2008/01/02 12:07:47 andy_seaborne Exp $
009: *****************************************************************/package com.hp.hpl.jena.reasoner.rulesys;
010:
011: import com.hp.hpl.jena.rdf.model.RDFNode;
012: import com.hp.hpl.jena.rdf.model.ResourceFactory;
013: import com.hp.hpl.jena.reasoner.rulesys.impl.*;
014: import com.hp.hpl.jena.reasoner.transitiveReasoner.*;
015: import com.hp.hpl.jena.reasoner.*;
016: import com.hp.hpl.jena.shared.ReificationStyle;
017: import com.hp.hpl.jena.shared.impl.JenaParameters;
018: import com.hp.hpl.jena.graph.*;
019:
020: import java.util.*;
021:
022: //import com.hp.hpl.jena.util.PrintUtil;
023: import com.hp.hpl.jena.util.OneToManyMap;
024: import com.hp.hpl.jena.util.PrintUtil;
025: import com.hp.hpl.jena.util.iterator.*;
026: import com.hp.hpl.jena.vocabulary.*;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030:
031: /**
032: * An inference graph that uses a mixture of forward and backward
033: * chaining rules. The forward rules can create direct deductions from
034: * the source data and schema and can also create backward rules. A
035: * query is answered by consulting the union of the raw data, the forward
036: * derived results and any relevant backward rules (whose answers are tabled
037: * for future reference).
038: *
039: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
040: * @version $Revision: 1.67 $ on $Date: 2008/01/02 12:07:47 $
041: */
042: public class FBRuleInfGraph extends BasicForwardRuleInfGraph implements
043: BackwardRuleInfGraphI {
044:
045: /** Single context for the reasoner, used when passing information to builtins */
046: protected BBRuleContext context;
047:
048: /** A finder that searches across the data, schema, axioms and forward deductions*/
049: protected Finder dataFind;
050:
051: /** The core backward rule engine which includes all the memoized results */
052: protected LPBRuleEngine bEngine;
053:
054: /** The original rule set as supplied */
055: protected List rawRules;
056:
057: /** The rule list after possible extension by preprocessing hooks */
058: protected List rules;
059:
060: /** Static switch from Basic to RETE implementation of the forward component */
061: public static boolean useRETE = true;
062:
063: /** Flag, if true then subClass and subProperty lattices will be optimized using TGCs */
064: protected boolean useTGCCaching = false;
065:
066: /** Flag, if true then find results will be filtered to remove functors and illegal RDF */
067: public boolean filterFunctors = true;
068:
069: /** Optional precomputed cache of the subClass/subproperty lattices */
070: protected TransitiveEngine transitiveEngine;
071:
072: /** Optional list of preprocessing hooks to be run in sequence during preparation time */
073: protected List preprocessorHooks;
074:
075: /** Cache of temporary property values inferred through getTemp calls */
076: protected TempNodeCache tempNodecache;
077:
078: /** Table of temp nodes which should be hidden from output listings */
079: protected Set hiddenNodes;
080:
081: static Log logger = LogFactory.getLog(FBRuleInfGraph.class);
082:
083: // =======================================================================
084: // Constructors
085:
086: /**
087: * Constructor.
088: * @param reasoner the reasoner which created this inf graph instance
089: * @param schema the (optional) schema graph to be included
090: */
091: public FBRuleInfGraph(Reasoner reasoner, Graph schema) {
092: super (reasoner, schema);
093: constructorInit(schema);
094: }
095:
096: /**
097: * Constructor.
098: * @param reasoner the reasoner which created this inf graph instance
099: * @param rules the rules to process
100: * @param schema the (optional) schema graph to be included
101: */
102: public FBRuleInfGraph(Reasoner reasoner, List rules, Graph schema) {
103: this (reasoner, rules, schema, ReificationStyle.Minimal);
104: }
105:
106: public FBRuleInfGraph(Reasoner reasoner, List rules, Graph schema,
107: ReificationStyle style) {
108: super (reasoner, rules, schema, style);
109: this .rawRules = rules;
110: constructorInit(schema);
111: }
112:
113: /**
114: * Constructor.
115: * @param reasoner the reasoner which created this inf graph instance
116: * @param rules the rules to process
117: * @param schema the (optional) schema graph to be included
118: * @param data the data graph to be processed
119: */
120: public FBRuleInfGraph(Reasoner reasoner, List rules, Graph schema,
121: Graph data) {
122: super (reasoner, rules, schema, data);
123: this .rawRules = rules;
124: constructorInit(schema);
125: }
126:
127: /**
128: * Common pieces of initialization code which apply in all constructor cases.
129: */
130: private void constructorInit(Graph schema) {
131: initLP(schema);
132: tempNodecache = new TempNodeCache(this );
133: if (JenaParameters.enableFilteringOfHiddenInfNodes) {
134: hiddenNodes = new HashSet();
135: if (schema != null && schema instanceof FBRuleInfGraph) {
136: hiddenNodes
137: .addAll(((FBRuleInfGraph) schema).hiddenNodes);
138: }
139: }
140: }
141:
142: /**
143: * Instantiate the forward rule engine to use.
144: * Subclasses can override this to switch to, say, a RETE imlementation.
145: * @param rules the rule set or null if there are not rules bound in yet.
146: */
147: protected void instantiateRuleEngine(List rules) {
148: if (rules != null) {
149: if (useRETE) {
150: engine = new RETEEngine(this , rules);
151: } else {
152: engine = new FRuleEngine(this , rules);
153: }
154: } else {
155: if (useRETE) {
156: engine = new RETEEngine(this );
157: } else {
158: engine = new FRuleEngine(this );
159: }
160: }
161: }
162:
163: /**
164: * Initialize the LP engine, based on an optional schema graph.
165: */
166: private void initLP(Graph schema) {
167: if (schema != null && schema instanceof FBRuleInfGraph) {
168: LPRuleStore newStore = new LPRuleStore();
169: newStore.addAll(((FBRuleInfGraph) schema).bEngine
170: .getRuleStore());
171: bEngine = new LPBRuleEngine(this , newStore);
172: } else {
173: bEngine = new LPBRuleEngine(this );
174: }
175: }
176:
177: /**
178: * Instantiate the optional caches for the subclass/suproperty lattices.
179: * Unless this call is made the TGC caching will not be used.
180: */
181: public void setUseTGCCache() {
182: useTGCCaching = true;
183: resetTGCCache();
184: }
185:
186: /**
187: * Rest the transitive graph caches
188: */
189: private void resetTGCCache() {
190: if (schemaGraph != null) {
191: transitiveEngine = new TransitiveEngine(
192: ((FBRuleInfGraph) schemaGraph).transitiveEngine);
193: } else {
194: transitiveEngine = new TransitiveEngine(
195: new TransitiveGraphCache(
196: ReasonerVocabulary.directSubClassOf
197: .asNode(), RDFS.subClassOf.asNode()),
198: new TransitiveGraphCache(
199: ReasonerVocabulary.directSubPropertyOf
200: .asNode(), RDFS.subPropertyOf
201: .asNode()));
202: }
203: }
204:
205: // =======================================================================
206: // Interface between infGraph and the goal processing machinery
207:
208: /**
209: * Search the combination of data and deductions graphs for the given triple pattern.
210: * This may different from the normal find operation in the base of hybrid reasoners
211: * where we are side-stepping the backward deduction step.
212: */
213: public ExtendedIterator findDataMatches(Node subject,
214: Node predicate, Node object) {
215: return dataFind.find(new TriplePattern(subject, predicate,
216: object));
217: }
218:
219: /**
220: * Search the combination of data and deductions graphs for the given triple pattern.
221: * This may different from the normal find operation in the base of hybrid reasoners
222: * where we are side-stepping the backward deduction step.
223: */
224: public ExtendedIterator findDataMatches(TriplePattern pattern) {
225: return dataFind.find(pattern);
226: }
227:
228: /**
229: * Process a call to a builtin predicate
230: * @param clause the Functor representing the call
231: * @param env the BindingEnvironment for this call
232: * @param rule the rule which is invoking this call
233: * @return true if the predicate succeeds
234: */
235: public boolean processBuiltin(ClauseEntry clause, Rule rule,
236: BindingEnvironment env) {
237: throw new ReasonerException(
238: "Internal error in FBLP rule engine, incorrect invocation of builtin in rule "
239: + rule);
240: // TODO: Remove
241: // if (clause instanceof Functor) {
242: // context.setEnv(env);
243: // context.setRule(rule);
244: // return((Functor)clause).evalAsBodyClause(context);
245: // } else {
246: // throw new ReasonerException("Illegal builtin predicate: " + clause + " in rule " + rule);
247: // }
248: }
249:
250: /**
251: * Adds a new Backward rule as a rusult of a forward rule process. Only some
252: * infgraphs support this.
253: */
254: public void addBRule(Rule brule) {
255: if (logger.isDebugEnabled()) {
256: logger.debug("Adding rule " + brule);
257: }
258: bEngine.addRule(brule);
259: bEngine.reset();
260: }
261:
262: /**
263: * Deletes a new Backward rule as a rules of a forward rule process. Only some
264: * infgraphs support this.
265: */
266: public void deleteBRule(Rule brule) {
267: if (logger.isDebugEnabled()) {
268: logger.debug("Deleting rule " + brule);
269: }
270: bEngine.deleteRule(brule);
271: bEngine.reset();
272: }
273:
274: /**
275: * Adds a set of new Backward rules
276: */
277: public void addBRules(List rules) {
278: for (Iterator i = rules.iterator(); i.hasNext();) {
279: Rule rule = (Rule) i.next();
280: // logger.debug("Adding rule " + rule);
281: bEngine.addRule(rule);
282: }
283: bEngine.reset();
284: }
285:
286: /**
287: * Return an ordered list of all registered backward rules. Includes those
288: * generated by forward productions.
289: */
290: public List getBRules() {
291: return bEngine.getAllRules();
292: }
293:
294: /**
295: * Return the originally supplied set of rules, may be a mix of forward
296: * and backward rules.
297: */
298: public List getRules() {
299: return rules;
300: }
301:
302: /**
303: * Set a predicate to be tabled/memoized by the LP engine.
304: */
305: public void setTabled(Node predicate) {
306: bEngine.tablePredicate(predicate);
307: if (traceOn) {
308: logger.info("LP TABLE " + predicate);
309: }
310: }
311:
312: /**
313: * Return a compiled representation of all the registered
314: * forward rules.
315: */
316: private Object getForwardRuleStore() {
317: return engine.getRuleStore();
318: }
319:
320: /**
321: * Add a new deduction to the deductions graph.
322: */
323: public void addDeduction(Triple t) {
324: getCurrentDeductionsGraph().add(t);
325: if (useTGCCaching) {
326: transitiveEngine.add(t);
327: }
328: }
329:
330: /**
331: * Retrieve or create a bNode representing an inferred property value.
332: * @param instance the base instance node to which the property applies
333: * @param prop the property node whose value is being inferred
334: * @param pclass the (optional, can be null) class for the inferred value.
335: * @return the bNode representing the property value
336: */
337: public Node getTemp(Node instance, Node prop, Node pclass) {
338: return tempNodecache.getTemp(instance, prop, pclass);
339: }
340:
341: // =======================================================================
342: // Core inf graph methods
343:
344: /**
345: * Add a new rule to the rule set. This should only be used by implementations
346: * of RuleProprocessHook (which are called during rule system preparation phase).
347: * If called at other times the rule won't be correctly transferred into the
348: * underlying engines.
349: */
350: public void addRuleDuringPrepare(Rule rule) {
351: if (rules == rawRules) {
352: // Ensure the original is preserved in case we need to do a restart
353: if (rawRules instanceof ArrayList) {
354: rules = (ArrayList) ((ArrayList) rawRules).clone();
355: } else {
356: rules = new ArrayList(rawRules);
357: }
358: // Rebuild the forward engine to use the cloned rules
359: instantiateRuleEngine(rules);
360: }
361: rules.add(rule);
362: }
363:
364: /**
365: * Add a new preprocessing hook defining an operation that
366: * should be run when the preparation phase is underway.
367: */
368: public void addPreprocessingHook(RulePreprocessHook hook) {
369: if (preprocessorHooks == null) {
370: preprocessorHooks = new ArrayList();
371: }
372: preprocessorHooks.add(hook);
373: }
374:
375: /**
376: * Perform any initial processing and caching. This call is optional. Most
377: * engines either have negligable set up work or will perform an implicit
378: * "prepare" if necessary. The call is provided for those occasions where
379: * substantial preparation work is possible (e.g. running a forward chaining
380: * rule system) and where an application might wish greater control over when
381: * this prepration is done.
382: */
383: public void prepare() {
384: if (!isPrepared) {
385: isPrepared = true;
386:
387: // Restore the original pre-hookProcess rules
388: rules = rawRules;
389:
390: // Is there any data to bind in yet?
391: Graph data = null;
392: if (fdata != null)
393: data = fdata.getGraph();
394:
395: // initilize the deductions graph
396: if (fdeductions != null && fdeductions instanceof FGraph) {
397: Graph oldDeductions = ((FGraph) fdeductions).getGraph();
398: oldDeductions.getBulkUpdateHandler().removeAll();
399: } else {
400: fdeductions = new FGraph(createDeductionsGraph());
401: }
402: dataFind = (data == null) ? fdeductions : FinderUtil
403: .cascade(fdeductions, fdata);
404: Finder dataSource = fdata;
405:
406: // Initialize the optional TGC caches
407: if (useTGCCaching) {
408: resetTGCCache();
409: if (schemaGraph != null) {
410: // Check if we can just reuse the copy of the raw
411: if ((transitiveEngine.checkOccurance(
412: TransitiveReasoner.subPropertyOf, data)
413: || transitiveEngine
414: .checkOccurance(
415: TransitiveReasoner.subClassOf,
416: data)
417: || transitiveEngine.checkOccurance(
418: RDFS.domain.asNode(), data) || transitiveEngine
419: .checkOccurance(RDFS.range.asNode(), data))) {
420:
421: // The data graph contains some ontology knowledge so split the caches
422: // now and rebuild them using merged data
423: transitiveEngine.insert(
424: ((FBRuleInfGraph) schemaGraph).fdata,
425: fdata);
426: }
427: } else {
428: if (data != null) {
429: transitiveEngine.insert(null, fdata);
430: }
431: }
432: // Insert any axiomatic statements into the caches
433: for (Iterator i = rules.iterator(); i.hasNext();) {
434: Rule r = (Rule) i.next();
435: if (r.bodyLength() == 0) {
436: // An axiom
437: for (int j = 0; j < r.headLength(); j++) {
438: Object head = r.getHeadElement(j);
439: if (head instanceof TriplePattern) {
440: TriplePattern h = (TriplePattern) head;
441: transitiveEngine.add(h.asTriple());
442: }
443: }
444: }
445: }
446:
447: transitiveEngine.setCaching(true, true);
448: // dataFind = FinderUtil.cascade(subClassCache, subPropertyCache, dataFind);
449: dataFind = FinderUtil.cascade(dataFind,
450: transitiveEngine.getSubClassCache(),
451: transitiveEngine.getSubPropertyCache());
452:
453: // Without the next statement then the transitive closures are not seen by the forward rules
454: dataSource = FinderUtil.cascade(dataSource,
455: transitiveEngine.getSubClassCache(),
456: transitiveEngine.getSubPropertyCache());
457: }
458:
459: // Make sure there are no Brules left over from pior runs
460: bEngine.deleteAllRules();
461:
462: // Call any optional preprocessing hook
463: if (preprocessorHooks != null
464: && preprocessorHooks.size() > 0) {
465: Graph inserts = Factory.createGraphMem();
466: for (Iterator i = preprocessorHooks.iterator(); i
467: .hasNext();) {
468: RulePreprocessHook hook = (RulePreprocessHook) i
469: .next();
470: hook.run(this , dataFind, inserts);
471: }
472: if (inserts.size() > 0) {
473: FGraph finserts = new FGraph(inserts);
474: dataSource = FinderUtil.cascade(fdata, finserts);
475: dataFind = FinderUtil.cascade(dataFind, finserts);
476: }
477: }
478:
479: boolean rulesLoaded = false;
480: if (schemaGraph != null) {
481: Graph rawPreload = ((InfGraph) schemaGraph)
482: .getRawGraph();
483: if (rawPreload != null) {
484: dataFind = FinderUtil.cascade(dataFind, new FGraph(
485: rawPreload));
486: }
487: rulesLoaded = preloadDeductions(schemaGraph);
488: }
489: if (rulesLoaded) {
490: engine.fastInit(dataSource);
491: } else {
492: // No preload so do the rule separation
493: addBRules(extractPureBackwardRules(rules));
494: engine.init(true, dataSource);
495: }
496: // Prepare the context for builtins run in backwards engine
497: context = new BBRuleContext(this );
498:
499: }
500: }
501:
502: /**
503: * Cause the inference graph to reconsult the underlying graph to take
504: * into account changes. Normally changes are made through the InfGraph's add and
505: * remove calls are will be handled appropriately. However, in some cases changes
506: * are made "behind the InfGraph's back" and this forces a full reconsult of
507: * the changed data.
508: */
509: public void rebind() {
510: version++;
511: if (bEngine != null)
512: bEngine.reset();
513: isPrepared = false;
514: }
515:
516: /**
517: * Cause the inference graph to reconsult both the underlying graph and
518: * the reasoner ruleset, permits the forward rule set to be dynamically changed.
519: * Causes the entire rule engine to be rebuilt from the current ruleset and
520: * reinitialized against the current data. Not needed for normal cases.
521: */
522: public void rebindAll() {
523: rawRules = ((FBRuleReasoner) reasoner).getRules();
524: instantiateRuleEngine(rawRules);
525: rebind();
526: }
527:
528: /**
529: * Set the state of the trace flag. If set to true then rule firings
530: * are logged out to the Log at "INFO" level.
531: */
532: public void setTraceOn(boolean state) {
533: super .setTraceOn(state);
534: bEngine.setTraceOn(state);
535: }
536:
537: /**
538: * Set to true to enable derivation caching
539: */
540: public void setDerivationLogging(boolean recordDerivations) {
541: this .recordDerivations = recordDerivations;
542: engine.setDerivationLogging(recordDerivations);
543: bEngine.setDerivationLogging(recordDerivations);
544: if (recordDerivations) {
545: derivations = new OneToManyMap();
546: } else {
547: derivations = null;
548: }
549: }
550:
551: /**
552: * Set to true to cause functor-valued literals to be dropped from rule output.
553: * Default is true.
554: */
555: public void setFunctorFiltering(boolean param) {
556: filterFunctors = param;
557: }
558:
559: /**
560: * Return the number of rules fired since this rule engine instance
561: * was created and initialized. The current implementation only counts
562: * forward rules and does not track dynamic backward rules needed for
563: * specific queries.
564: */
565: public long getNRulesFired() {
566: return engine.getNRulesFired();
567: }
568:
569: /**
570: * Extended find interface used in situations where the implementator
571: * may or may not be able to answer the complete query. It will
572: * attempt to answer the pattern but if its answers are not known
573: * to be complete then it will also pass the request on to the nested
574: * Finder to append more results.
575: * @param pattern a TriplePattern to be matched against the data
576: * @param continuation either a Finder or a normal Graph which
577: * will be asked for additional match results if the implementor
578: * may not have completely satisfied the query.
579: */
580: public ExtendedIterator findWithContinuation(TriplePattern pattern,
581: Finder continuation) {
582: checkOpen();
583: if (!isPrepared)
584: prepare();
585: ExtendedIterator result = new UniqueExtendedIterator(bEngine
586: .find(pattern));
587: if (continuation != null) {
588: result = result.andThen(continuation.find(pattern));
589: }
590: if (filterFunctors) {
591: // return result.filterDrop(Functor.acceptFilter);
592: return result.filterDrop(new Filter() {
593:
594: public boolean accept(Object o) {
595: return FBRuleInfGraph.this .accept(o);
596: }
597: });
598: } else {
599: return result;
600: }
601: }
602:
603: /**
604: * Internal variant of find which omits the filters which block illegal RDF data.
605: * @param pattern a TriplePattern to be matched against the data
606: */
607: public ExtendedIterator findFull(TriplePattern pattern) {
608: checkOpen();
609: if (!isPrepared)
610: prepare();
611: return new UniqueExtendedIterator(bEngine.find(pattern));
612: }
613:
614: /**
615: * Returns an iterator over Triples.
616: * This implementation assumes that the underlying findWithContinuation
617: * will have also consulted the raw data.
618: */
619: public ExtendedIterator graphBaseFind(Node subject, Node property,
620: Node object) {
621: return findWithContinuation(new TriplePattern(subject,
622: property, object), null);
623: }
624:
625: /**
626: * Basic pattern lookup interface.
627: * This implementation assumes that the underlying findWithContinuation
628: * will have also consulted the raw data.
629: * @param pattern a TriplePattern to be matched against the data
630: * @return a ExtendedIterator over all Triples in the data set
631: * that match the pattern
632: */
633: public ExtendedIterator find(TriplePattern pattern) {
634: return findWithContinuation(pattern, null);
635: }
636:
637: /**
638: * Flush out all cached results. Future queries have to start from scratch.
639: */
640: public void reset() {
641: version++;
642: bEngine.reset();
643: isPrepared = false;
644: }
645:
646: /**
647: * Add one triple to the data graph, run any rules triggered by
648: * the new data item, recursively adding any generated triples.
649: */
650: public synchronized void performAdd(Triple t) {
651: version++;
652: fdata.getGraph().add(t);
653: if (useTGCCaching) {
654: if (transitiveEngine.add(t))
655: isPrepared = false;
656: }
657: if (isPrepared) {
658: boolean needReset = false;
659: if (preprocessorHooks != null
660: && preprocessorHooks.size() > 0) {
661: if (preprocessorHooks.size() > 1) {
662: for (Iterator i = preprocessorHooks.iterator(); i
663: .hasNext();) {
664: if (((RulePreprocessHook) i.next()).needsRerun(
665: this , t)) {
666: needReset = true;
667: break;
668: }
669: }
670: } else {
671: needReset = ((RulePreprocessHook) preprocessorHooks
672: .get(0)).needsRerun(this , t);
673: }
674: }
675: if (needReset) {
676: isPrepared = false;
677: } else {
678: engine.add(t);
679: }
680: }
681: bEngine.reset();
682: }
683:
684: /**
685: * Removes the triple t (if possible) from the set belonging to this graph.
686: */
687: public void performDelete(Triple t) {
688: version++;
689: boolean removeIsFromBase = fdata.getGraph().contains(t);
690: fdata.getGraph().delete(t);
691: if (useTGCCaching) {
692: if (transitiveEngine.delete(t)) {
693: if (isPrepared) {
694: bEngine.deleteAllRules();
695: }
696: isPrepared = false;
697: }
698: }
699: // Full incremental remove processing requires reference counting
700: // of all deductions. It's not clear the cost of maintaining the
701: // reference counts is worth it so the current implementation
702: // forces a recompute if any external deletes are performed.
703: if (isPrepared) {
704: bEngine.deleteAllRules();
705: isPrepared = false;
706: // Re-enable the code below when/if ref counting is added and remove above
707: // if (removeIsFromBase) engine.delete(t);
708: }
709: bEngine.reset();
710: }
711:
712: /**
713: * Return a new inference graph which is a clone of the current graph
714: * together with an additional set of data premises. Attempts to the replace
715: * the default brute force implementation by one that can reuse some of the
716: * existing deductions.
717: */
718: // This implementatin was incomplete. By commenting it out we revert to
719: // the global brute force solution of cloning the full graph
720: // public InfGraph cloneWithPremises(Graph premises) {
721: // prepare();
722: // FBRuleInfGraph graph = new FBRuleInfGraph(getReasoner(), rawRules, this);
723: // if (useTGCCaching) graph.setUseTGCCache();
724: // graph.setDerivationLogging(recordDerivations);
725: // graph.setTraceOn(traceOn);
726: // // Implementation note: whilst current tests pass its not clear that
727: // // the nested passing of FBRuleInfGraph's will correctly handle all
728: // // cases of indirectly bound schema data. If we do uncover a problem here
729: // // then either include the raw schema in a Union with the premises or
730: // // revert of a more brute force version.
731: // graph.rebind(premises);
732: // return graph;
733: // }
734: /**
735: * Free all resources, any further use of this Graph is an error.
736: */
737: public void close() {
738: if (!closed) {
739: bEngine.halt();
740: bEngine = null;
741: transitiveEngine = null;
742: super .close();
743: }
744: }
745:
746: // =======================================================================
747: // Generalized validation machinery. Assumes rule set has special validation
748: // rules that can be turned on.
749:
750: /**
751: * Test the consistency of the bound data. This normally tests
752: * the validity of the bound instance data against the bound
753: * schema data.
754: * @return a ValidityReport structure
755: */
756: public ValidityReport validate() {
757: checkOpen();
758: StandardValidityReport report = new StandardValidityReport();
759: // Switch on validation
760: Triple validateOn = new Triple(Node.createAnon(),
761: ReasonerVocabulary.RB_VALIDATION.asNode(), Functor
762: .makeFunctorNode("on", new Node[] {}));
763: // We sneak this switch directly into the engine to avoid contaminating the
764: // real data - this is only possible only the forward engine has been prepared
765: // add(validateOn);
766: if (!isPrepared) {
767: prepare();
768: }
769: engine.add(validateOn);
770: // Look for all reports
771: TriplePattern pattern = new TriplePattern(null,
772: ReasonerVocabulary.RB_VALIDATION_REPORT.asNode(), null);
773: for (Iterator i = findFull(pattern); i.hasNext();) {
774: Triple t = (Triple) i.next();
775: Node rNode = t.getObject();
776: boolean foundReport = false;
777: if (rNode.isLiteral()) {
778: Object rVal = rNode.getLiteralValue();
779: if (rVal instanceof Functor) {
780: Functor rFunc = (Functor) rVal;
781: foundReport = true;
782: StringBuffer description = new StringBuffer();
783: String nature = rFunc.getName();
784: String type = rFunc.getArgs()[0].toString();
785: String text = rFunc.getArgs()[1].toString();
786: description.append(text + "\n");
787: description.append("Culprit = "
788: + PrintUtil.print(t.getSubject()) + "\n");
789: for (int j = 2; j < rFunc.getArgLength(); j++) {
790: description.append("Implicated node: "
791: + PrintUtil.print(rFunc.getArgs()[j])
792: + "\n");
793: }
794: Node culpritN = t.getSubject();
795: RDFNode culprit = null;
796: if (culpritN.isURI()) {
797: culprit = ResourceFactory
798: .createResource(culpritN.getURI());
799: }
800: report.add(nature.equalsIgnoreCase("error"), type,
801: description.toString(), culprit);
802: }
803: }
804: }
805: // // Debug
806: // Node ia = Node.createURI("http://jena.hpl.hp.com/testing/reasoners/owl#ia");
807: // System.out.println("Types of ia");
808: // PrintUtil.printOut(findFull(new TriplePattern(ia, RDF.Nodes.type, null)));
809: // System.out.println("different froms");
810: // PrintUtil.printOut(findFull(new TriplePattern(null, OWL.differentFrom.asNode(), null)));
811: // System.out.println("ia same as");
812: // PrintUtil.printOut(findFull(new TriplePattern(ia, OWL.sameIndividualAs.asNode(), null)));
813: // // end
814: return report;
815: }
816:
817: // =======================================================================
818: // Helper methods
819:
820: /**
821: * Scan the initial rule set and pick out all the backward-only rules with non-null bodies,
822: * and transfer these rules to the backward engine.
823: */
824: private static List extractPureBackwardRules(List rules) {
825: List bRules = new ArrayList();
826: for (Iterator i = rules.iterator(); i.hasNext();) {
827: Rule r = (Rule) i.next();
828: if (r.isBackward() && r.bodyLength() > 0) {
829: bRules.add(r);
830: }
831: }
832: return bRules;
833: }
834:
835: /**
836: * Adds a set of precomputed triples to the deductions store. These do not, themselves,
837: * fire any rules but provide additional axioms that might enable future rule
838: * firing when real data is added. Used to implement bindSchema processing
839: * in the parent Reasoner.
840: * @return true if the preload was able to load rules as well
841: */
842: protected boolean preloadDeductions(Graph preloadIn) {
843: Graph d = fdeductions.getGraph();
844: FBRuleInfGraph preload = (FBRuleInfGraph) preloadIn;
845: // If the rule set is the same we can reuse those as well
846: if (preload.rules == rules) {
847: // Load raw deductions
848: for (Iterator i = preload.getDeductionsGraph().find(null,
849: null, null); i.hasNext();) {
850: d.add((Triple) i.next());
851: }
852: // Load backward rules
853: addBRules(preload.getBRules());
854: // Load forward rules
855: engine.setRuleStore(preload.getForwardRuleStore());
856: // Add access to raw data
857: return true;
858: } else {
859: return false;
860: }
861: }
862:
863: /**
864: * Called to flag that a node should be hidden from external queries.
865: */
866: public void hideNode(Node n) {
867: if (!JenaParameters.enableFilteringOfHiddenInfNodes)
868: return;
869: if (hiddenNodes == null) {
870: hiddenNodes = new HashSet();
871: }
872: synchronized (hiddenNodes) {
873: hiddenNodes.add(n);
874: }
875: }
876:
877: // =======================================================================
878: // Support for LP engine profiling
879:
880: /**
881: * Reset the LP engine profile.
882: * @param enable it true then profiling will continue with a new empty profile table,
883: * if false profiling will stop all current data lost.
884: */
885: public void resetLPProfile(boolean enable) {
886: bEngine.resetProfile(enable);
887: }
888:
889: /**
890: * Print a profile of LP rules used since the last reset.
891: */
892: public void printLPProfile() {
893: bEngine.printProfile();
894: }
895:
896: // =======================================================================
897: // Implement Filter signature
898:
899: /**
900: * Post-filter query results to hide unwanted
901: * triples from the glare of publicity. Unwanted triples
902: * are triples with Functor literals and triples with hidden nodes
903: * as subject or object.
904: */
905: public boolean accept(Object tin) {
906: Triple t = (Triple) tin;
907:
908: if (((Triple) t).getSubject().isLiteral())
909: return true;
910:
911: if (JenaParameters.enableFilteringOfHiddenInfNodes
912: && hiddenNodes != null) {
913: if (hiddenNodes.contains(t.getSubject())
914: || hiddenNodes.contains(t.getObject())
915: || hiddenNodes.contains(t.getPredicate())) {
916: return true;
917: }
918: }
919:
920: if (filterFunctors) {
921: if (Functor.isFunctor(t.getObject())) {
922: return true;
923: }
924: }
925:
926: return false;
927:
928: }
929:
930: // =======================================================================
931: // Inner classes
932:
933: /**
934: * Structure used to wrap up pre-processed/compiled rule sets.
935: */
936: public static class RuleStore {
937:
938: /** The raw rules */
939: protected List rawRules;
940:
941: /** The indexed store used by the forward chainer */
942: protected Object fRuleStore;
943:
944: /** The separated backward rules */
945: protected List bRules;
946:
947: /**
948: * Constructor.
949: */
950: public RuleStore(List rawRules, Object fRuleStore, List bRules) {
951: this .rawRules = rawRules;
952: this .fRuleStore = fRuleStore;
953: this .bRules = bRules;
954: }
955:
956: }
957:
958: }
959:
960: /*
961: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
962: All rights reserved.
963:
964: Redistribution and use in source and binary forms, with or without
965: modification, are permitted provided that the following conditions
966: are met:
967:
968: 1. Redistributions of source code must retain the above copyright
969: notice, this list of conditions and the following disclaimer.
970:
971: 2. Redistributions in binary form must reproduce the above copyright
972: notice, this list of conditions and the following disclaimer in the
973: documentation and/or other materials provided with the distribution.
974:
975: 3. The name of the author may not be used to endorse or promote products
976: derived from this software without specific prior written permission.
977:
978: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
979: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
980: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
981: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
982: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
983: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
984: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
985: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
986: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
987: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
988: */
|