001: /******************************************************************
002: * File: BaseInfGraph.java
003: * Created by: Dave Reynolds
004: * Created on: 18-Jan-03
005: *
006: * (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
007: * [See end of file]
008: * $Id: BaseInfGraph.java,v 1.48 2008/01/02 12:07:00 andy_seaborne Exp $
009: *****************************************************************/package com.hp.hpl.jena.reasoner;
010:
011: import com.hp.hpl.jena.graph.*;
012: import com.hp.hpl.jena.graph.compose.MultiUnion;
013: import com.hp.hpl.jena.graph.compose.Union;
014: import com.hp.hpl.jena.graph.impl.*;
015: import com.hp.hpl.jena.shared.*;
016: import com.hp.hpl.jena.util.iterator.*;
017: import java.util.Iterator;
018:
019: /**
020: * A base level implementation of the InfGraph interface.
021: *
022: * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>
023: * @version $Revision: 1.48 $ on $Date: 2008/01/02 12:07:00 $
024: */
025: public abstract class BaseInfGraph extends GraphBase implements
026: InfGraph {
027:
028: /** The Reasoner instance which performs all inferences and Tbox lookups */
029: protected Reasoner reasoner;
030:
031: /** The graph of raw data which is being reasoned over */
032: protected FGraph fdata;
033:
034: /** Flag, if set to true then derivations are recorded */
035: protected boolean recordDerivations;
036:
037: /** Flag to record if the preparation call has been made and so the graph is ready for queries */
038: protected boolean isPrepared = false;
039:
040: /** version count */
041: protected volatile int version = 0;
042:
043: /**
044: Inference graphs share the prefix-mapping of their underlying raw graph.
045: @see com.hp.hpl.jena.graph.Graph#getPrefixMapping()
046: */
047: public PrefixMapping getPrefixMapping() {
048: return getRawGraph().getPrefixMapping();
049: }
050:
051: /**
052: Inference graphs share the reifiers of their underlying raw graphs. This may
053: be too simplistic - they won't see quads flying past.
054: TODO write a test case that reveals this.
055: @see com.hp.hpl.jena.graph.Graph#getReifier()
056: */
057: public Reifier constructReifier() {
058: return getRawGraph().getReifier();
059: }
060:
061: /**
062: * Constructor
063: * @param data the raw data file to be augmented with entailments
064: * @param reasoner the engine, with associated tbox data, whose find interface
065: * can be used to extract all entailments from the data.
066: */
067: public BaseInfGraph(Graph data, Reasoner reasoner) {
068: this (data, reasoner, ReificationStyle.Minimal); // should pick style from data? TODO
069: }
070:
071: public BaseInfGraph(Graph data, Reasoner reasoner,
072: ReificationStyle style) {
073: super (style);
074: this .fdata = new FGraph(data);
075: this .reasoner = reasoner;
076: }
077:
078: /**
079: Answer the InfCapabilities of this InfGraph.
080: */
081: public Capabilities getCapabilities() {
082: if (capabilities == null) {
083: return getReasoner().getGraphCapabilities();
084: } else {
085: return capabilities;
086: }
087: }
088:
089: /**
090: An InfCapabilities notes that size may not be accurate, and some
091: triples may be irremovable.
092:
093: TODO accomodate the properties of the base graph, too.
094:
095: @author hedgehog
096: */
097: public static class InfCapabilities extends AllCapabilities {
098: public boolean sizeAccurate() {
099: return false;
100: }
101:
102: public boolean deleteAllowed(boolean every) {
103: return !every;
104: }
105:
106: public boolean iteratorRemoveAllowed() {
107: return false;
108: }
109:
110: public boolean findContractSafe() {
111: return false;
112: }
113: }
114:
115: /**
116: An InfCapabilities notes that size may not be accurate, and some
117: triples may be irremovable.
118:
119: TODO accomodate the properties of the base graph, too.
120:
121: @author hedgehog
122: */
123: public static class InfFindSafeCapabilities extends InfCapabilities {
124: public boolean findContractSafe() {
125: return true;
126: }
127: }
128:
129: public BulkUpdateHandler getBulkUpdateHandler() {
130: if (bulkHandler == null)
131: bulkHandler = new InfBulkUpdateHandler(this );
132: return bulkHandler;
133: }
134:
135: /**
136: InfBulkUpdateHandler - a bulk update handler specialised for inference
137: graphs by code for <code>removeAll()</code>.
138:
139: @author kers
140: */
141: static class InfBulkUpdateHandler extends SimpleBulkUpdateHandler {
142: public InfBulkUpdateHandler(BaseInfGraph graph) {
143: super (graph);
144: }
145:
146: public void remove(Node s, Node p, Node o) {
147: BaseInfGraph g = (BaseInfGraph) graph;
148: g.getRawGraph().getBulkUpdateHandler().remove(s, p, o);
149: g.discardState();
150: g.rebind();
151: manager.notifyEvent(graph, GraphEvents.remove(s, p, o));
152: }
153:
154: public void removeAll() {
155: BaseInfGraph g = (BaseInfGraph) graph;
156: g.getRawGraph().getBulkUpdateHandler().removeAll();
157: g.discardState();
158: g.rebind();
159: g.getEventManager().notifyEvent(g, GraphEvents.removeAll);
160: }
161: }
162:
163: public TransactionHandler getTransactionHandler() {
164: return new InfTransactionHandler(this );
165: }
166:
167: public static class InfTransactionHandler extends
168: TransactionHandlerBase implements TransactionHandler {
169: protected final BaseInfGraph base;
170:
171: public InfTransactionHandler(BaseInfGraph base) {
172: this .base = base;
173: }
174:
175: public boolean transactionsSupported() {
176: return getBaseHandler().transactionsSupported();
177: }
178:
179: protected TransactionHandler getBaseHandler() {
180: return base.getRawGraph().getTransactionHandler();
181: }
182:
183: public void begin() {
184: getBaseHandler().begin();
185: }
186:
187: public void abort() {
188: getBaseHandler().abort();
189: base.rebind();
190: }
191:
192: public void commit() {
193: getBaseHandler().commit();
194: }
195: }
196:
197: /**
198: discard any state that depends on the content of fdata, because
199: it's just been majorly trashed, solid gone.
200: */
201: protected void discardState() {
202: }
203:
204: /**
205: * Return the raw RDF data Graph being processed (i.e. the argument
206: * to the Reasonder.bind call that created this InfGraph).
207: */
208: public Graph getRawGraph() {
209: return fdata.getGraph();
210: }
211:
212: /**
213: * Return the Reasoner which is being used to answer queries to this graph.
214: */
215: public Reasoner getReasoner() {
216: return reasoner;
217: }
218:
219: /**
220: * Replace the underlying data graph for this inference graph and start any
221: * inferences over again. This is primarily using in setting up ontology imports
222: * processing to allow an imports multiunion graph to be inserted between the
223: * inference graph and the raw data, before processing.
224: * @param data the new raw data graph
225: */
226: public void rebind(Graph data) {
227: fdata = new FGraph(data);
228: isPrepared = false;
229: }
230:
231: /**
232: * Cause the inference graph to reconsult the underlying graph to take
233: * into account changes. Normally changes are made through the InfGraph's add and
234: * remove calls are will be handled appropriately. However, in some cases changes
235: * are made "behind the InfGraph's back" and this forces a full reconsult of
236: * the changed data.
237: */
238: public void rebind() {
239: version++;
240: isPrepared = false;
241: }
242:
243: /**
244: * Reset any internal caches. Some systems, such as the tabled backchainer,
245: * retain information after each query. A reset will wipe this information preventing
246: * unbounded memory use at the expense of more expensive future queries. A reset
247: * does not cause the raw data to be reconsulted and so is less expensive than a rebind.
248: */
249: public void reset() {
250: version++;
251: }
252:
253: /**
254: * Perform any initial processing and caching. This call is optional. Most
255: * engines either have negligable set up work or will perform an implicit
256: * "prepare" if necessary. The call is provided for those occasions where
257: * substantial preparation work is possible (e.g. running a forward chaining
258: * rule system) and where an application might wish greater control over when
259: * this prepration is done.
260: */
261: public void prepare() {
262: // Default is to do no preparation
263: isPrepared = true;
264: }
265:
266: /**
267: * Returns a derivations graph. The rule reasoners typically create a
268: * graph containing those triples added to the base graph due to rule firings.
269: * In some applications it can useful to be able to access those deductions
270: * directly, without seeing the raw data which triggered them. In particular,
271: * this allows the forward rules to be used as if they were rewrite transformation
272: * rules.
273: * @return the deductions graph, if relevant for this class of inference
274: * engine or null if not.
275: */
276: public Graph getDeductionsGraph() {
277: return null;
278: }
279:
280: /**
281: * Test a global boolean property of the graph. This might included
282: * properties like consistency, OWLSyntacticValidity etc.
283: * It remains to be seen what level of generality is needed here. We could
284: * replace this by a small number of specific tests for common concepts.
285: * @param property the URI of the property to be tested
286: * @return a Node giving the value of the global property, this may
287: * be a boolean literal, some other literal value (e.g. a size).
288: */
289: public Node getGlobalProperty(Node property) {
290: throw new ReasonerException("Global property not implemented: "
291: + property);
292: }
293:
294: /**
295: * A convenience version of getGlobalProperty which can only return
296: * a boolean result.
297: */
298: public boolean testGlobalProperty(Node property) {
299: Node resultNode = getGlobalProperty(property);
300: if (resultNode.isLiteral()) {
301: Object result = resultNode.getLiteralValue();
302: if (result instanceof Boolean) {
303: return ((Boolean) result).booleanValue();
304: }
305: }
306: throw new ReasonerException(
307: "Global property test returned non-boolean value"
308: + "\nTest was: " + property + "\nResult was: "
309: + resultNode);
310: }
311:
312: /**
313: * Test the consistency of the bound data. This normally tests
314: * the validity of the bound instance data against the bound
315: * schema data.
316: * @return a ValidityReport structure
317: */
318: public ValidityReport validate() {
319: checkOpen();
320: return new StandardValidityReport();
321: }
322:
323: /**
324: * An extension of the Graph.find interface which allows the caller to
325: * encode complex expressions in RDF and then refer to those expressions
326: * within the query triple. For example, one might encode a class expression
327: * and then ask if there are any instances of this class expression in the
328: * InfGraph.
329: * @param subject the subject Node of the query triple, may be a Node in
330: * the graph or a node in the parameter micro-graph or null
331: * @param property the property to be retrieved or null
332: * @param object the object Node of the query triple, may be a Node in
333: * the graph or a node in the parameter micro-graph.
334: * @param param a small graph encoding an expression which the subject and/or
335: * object nodes refer.
336: */
337: public ExtendedIterator find(Node subject, Node property,
338: Node object, Graph param) {
339: return cloneWithPremises(param).find(subject, property, object);
340: }
341:
342: /**
343: * Returns an iterator over Triples.
344: *
345: * <p>This code used to have the .filterKeep component uncommented. We
346: * think this is because of earlier history, before .matches on a literal node
347: * was implemented as sameValueAs rather than equals. If it turns out that
348: * the filter is needed, it can be commented back in, AND a corresponding
349: * filter added to find(Node x 3) -- and test cases, of course.
350: *
351: * <p>[Chris, after discussion with Dave]
352: */
353: public ExtendedIterator graphBaseFind(TripleMatch m) {
354: return graphBaseFind(m.getMatchSubject(),
355: m.getMatchPredicate(), m.getMatchObject())
356: // .filterKeep(new TripleMatchFilter(m.asTriple()))
357: ;
358: }
359:
360: /**
361: * Returns an iterator over Triples.
362: * This implementation assumes that the underlying findWithContinuation
363: * will have also consulted the raw data.
364: */
365: public ExtendedIterator graphBaseFind(Node subject, Node property,
366: Node object) {
367: return findWithContinuation(new TriplePattern(subject,
368: property, object), fdata);
369: }
370:
371: /**
372: * Extended find interface used in situations where the implementator
373: * may or may not be able to answer the complete query. It will
374: * attempt to answer the pattern but if its answers are not known
375: * to be complete then it will also pass the request on to the nested
376: * Finder to append more results.
377: * @param pattern a TriplePattern to be matched against the data
378: * @param continuation either a Finder or a normal Graph which
379: * will be asked for additional match results if the implementor
380: * may not have completely satisfied the query.
381: */
382: abstract public ExtendedIterator findWithContinuation(
383: TriplePattern pattern, Finder continuation);
384:
385: /**
386: * Basic pattern lookup interface.
387: * This implementation assumes that the underlying findWithContinuation
388: * will have also consulted the raw data.
389: * @param pattern a TriplePattern to be matched against the data
390: * @return a ExtendedIterator over all Triples in the data set
391: * that match the pattern
392: */
393: public ExtendedIterator find(TriplePattern pattern) {
394: checkOpen();
395: return findWithContinuation(pattern, fdata);
396: }
397:
398: /**
399: * Switch on/off drivation logging
400: */
401: public void setDerivationLogging(boolean logOn) {
402: recordDerivations = logOn;
403: }
404:
405: /**
406: * Return the derivation of the given triple (which is the result of
407: * some previous find operation).
408: * Not all reasoneers will support derivations.
409: * @return an iterator over Derivation records or null if there is no derivation information
410: * available for this triple.
411: */
412: public Iterator getDerivation(Triple triple) {
413: return null;
414: }
415:
416: /**
417: * Return the number of triples in the just the base graph
418: */
419: public int graphBaseSize() {
420: checkOpen();
421: return fdata.getGraph().size();
422: }
423:
424: /**
425: Answer true iff this graph is empty. [Used to be in QueryHandler, but moved in
426: here because it's a more primitive operation.]
427: */
428: public boolean isEmpty() {
429: return fdata.getGraph().isEmpty();
430: }
431:
432: /**
433: * Free all resources, any further use of this Graph is an error.
434: */
435: public void close() {
436: if (!closed) {
437: fdata.getGraph().close();
438: fdata = null;
439: super .close();
440: }
441: }
442:
443: /**
444: * Return a version stamp for this graph which can be
445: * used to fast-fail concurrent modification exceptions.
446: */
447: public int getVersion() {
448: return version;
449: }
450:
451: /**
452: * Add one triple to the data graph, run any rules triggered by
453: * the new data item, recursively adding any generated triples.
454: */
455: public synchronized void performAdd(Triple t) {
456: version++;
457: if (!isPrepared)
458: prepare();
459: fdata.getGraph().add(t);
460: }
461:
462: /**
463: * Removes the triple t (if possible) from the set belonging to this graph.
464: */
465: public void performDelete(Triple t) {
466: version++;
467: if (!isPrepared)
468: prepare();
469: fdata.getGraph().delete(t);
470: }
471:
472: /**
473: * Return the schema graph, if any, bound into this inference graph.
474: */
475: public abstract Graph getSchemaGraph();
476:
477: /**
478: * Return a new inference graph which is a clone of the current graph
479: * together with an additional set of data premises. The default
480: * implementation loses ALL partial deductions so far. Some subclasses
481: * may be able to a more efficient job.
482: */
483: public InfGraph cloneWithPremises(Graph premises) {
484: MultiUnion union = new MultiUnion();
485: Graph raw = getRawGraph();
486: union.addGraph(raw);
487: union.setBaseGraph(raw);
488: union.addGraph(premises);
489: Graph schema = getSchemaGraph();
490: if (schema != null) {
491: if (schema instanceof BaseInfGraph) {
492: BaseInfGraph ischema = (BaseInfGraph) schema;
493: Graph sschema = ischema.getSchemaGraph();
494: if (sschema != null)
495: union.addGraph(sschema);
496: Graph rschema = ischema.getRawGraph();
497: if (rschema != null)
498: union.addGraph(rschema);
499: }
500:
501: }
502: return getReasoner().bind(union);
503: }
504:
505: /**
506: Answer true iff this graph has been through the <code>prepare()</code> step.
507: For testing purposes.
508: */
509: public boolean isPrepared() {
510: return isPrepared;
511: }
512:
513: }
514:
515: /*
516: (c) Copyright 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
517: All rights reserved.
518:
519: Redistribution and use in source and binary forms, with or without
520: modification, are permitted provided that the following conditions
521: are met:
522:
523: 1. Redistributions of source code must retain the above copyright
524: notice, this list of conditions and the following disclaimer.
525:
526: 2. Redistributions in binary form must reproduce the above copyright
527: notice, this list of conditions and the following disclaimer in the
528: documentation and/or other materials provided with the distribution.
529:
530: 3. The name of the author may not be used to endorse or promote products
531: derived from this software without specific prior written permission.
532:
533: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
534: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
535: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
536: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
537: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
538: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
539: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
540: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
541: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
542: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
543: */
|