001: /*****************************************************************************
002: * Source code information
003: * -----------------------
004: * Original author Ian Dickinson, HP Labs Bristol
005: * Author email Ian.Dickinson@hp.com
006: * Package Jena 2
007: * Web http://sourceforge.net/projects/jena/
008: * Created July 19th 2003
009: * Filename $RCSfile: DIGQueryTranslator.java,v $
010: * Revision $Revision: 1.20 $
011: * Release status $State: Exp $
012: *
013: * Last modified on $Date: 2008/01/02 12:07:10 $
014: * by $Author: andy_seaborne $
015: *
016: * (c) Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
017: * [See end of file]
018: * ****************************************************************************/package com.hp.hpl.jena.reasoner.dig;
019:
020: // Imports
021: ///////////////
022: import java.util.*;
023: import java.util.Iterator;
024: import java.util.List;
025:
026: import org.apache.commons.logging.LogFactory;
027: import org.w3c.dom.Document;
028: import org.w3c.dom.Element;
029:
030: import com.hp.hpl.jena.graph.*;
031: import com.hp.hpl.jena.rdf.model.Model;
032: import com.hp.hpl.jena.reasoner.TriplePattern;
033: import com.hp.hpl.jena.reasoner.rulesys.Node_RuleVariable;
034: import com.hp.hpl.jena.util.iterator.*;
035: import com.hp.hpl.jena.util.xml.SimpleXMLPath;
036: import com.hp.hpl.jena.util.xml.SimpleXMLPathElement;
037:
038: /**
039: * <p>
040: * Base class for translators that map incoming RDF find patterns to DIG queries.
041: * </p>
042: *
043: * @author Ian Dickinson, HP Labs (<a href="mailto:Ian.Dickinson@hp.com">email</a>)
044: * @version Release @release@ ($Id: DIGQueryTranslator.java,v 1.20 2008/01/02 12:07:10 andy_seaborne Exp $)
045: */
046: public abstract class DIGQueryTranslator {
047: // Constants
048: //////////////////////////////////
049:
050: public static final String ALL = "*";
051:
052: // Static variables
053: //////////////////////////////////
054:
055: // Instance variables
056: //////////////////////////////////
057:
058: /** The node that the incoming subject must match */
059: private Node m_subject;
060:
061: /** The node that the incoming object must match */
062: private Node m_object;
063:
064: /** The node that the incoming predicate must match */
065: private Node m_pred;
066:
067: // Constructors
068: //////////////////////////////////
069:
070: /**
071: * <p>Construct an abstract translator, given the URI's of nodes to match against
072: * or null to represent
073: */
074: public DIGQueryTranslator(String subject, String predicate,
075: String object) {
076: m_subject = mapNode(subject);
077: m_pred = mapNode(predicate);
078: m_object = mapNode(object);
079: }
080:
081: // External signature methods
082: //////////////////////////////////
083:
084: /**
085: * <p>Translate the given pattern to a DIG query, and pass it on to the DIG
086: * adapter as a query. Translate the results of the query back to a
087: * triple stream via an extended iterator. Assumes this method is called
088: * contingent on a successful {@link #trigger}.</p>
089: * @param pattern The pattern to translate to a DIG query
090: * @param da The DIG adapter through which we communicate with a DIG reasoner
091: */
092: public ExtendedIterator find(TriplePattern pattern, DIGAdapter da) {
093: DIGConnection dc = da.getConnection();
094:
095: // pose the query to the dig reasoner
096: Document query = translatePattern(pattern, da);
097: if (query == null) {
098: LogFactory.getLog(getClass()).warn(
099: "Could not find pattern translator for nested DIG query "
100: + pattern);
101: }
102: Document response = da.getConnection().sendDigVerb(query,
103: da.getProfile());
104:
105: boolean warn = dc.warningCheck(response);
106: if (warn) {
107: for (Iterator i = dc.getWarnings(); i.hasNext();) {
108: LogFactory.getLog(getClass()).warn(i.next());
109: }
110: }
111:
112: // translate the response back to triples
113: return translateResponse(response, pattern, da);
114: }
115:
116: /**
117: * <p>Translate the given pattern (with given premises)
118: * to a DIG query, and pass it on to the DIG
119: * adapter as a query. Translate the results of the query back to a
120: * triple stream via an extended iterator.</p>
121: * @param pattern The pattern to translate to a DIG query
122: * @param da The DIG adapter through which we communicate with a DIG reasoner
123: * @param premises Model conveying additional information about the resources
124: * in the subject or object
125: */
126: public ExtendedIterator find(TriplePattern pattern, DIGAdapter da,
127: Model premises) {
128: DIGConnection dc = da.getConnection();
129:
130: // pose the query to the dig reasoner
131: Document query = translatePattern(pattern, da, premises);
132: if (query == null) {
133: LogFactory.getLog(getClass()).warn(
134: "Could not find pattern translator for nested DIG query "
135: + pattern);
136: return NullIterator.instance;
137: } else {
138: Document response = da.getConnection().sendDigVerb(query,
139: da.getProfile());
140:
141: boolean warn = dc.warningCheck(response);
142: if (warn) {
143: for (Iterator i = dc.getWarnings(); i.hasNext();) {
144: LogFactory.getLog(getClass()).warn(i.next());
145: }
146: }
147:
148: // translate the response back to triples
149: return translateResponse(response, pattern, da);
150: }
151: }
152:
153: /**
154: * <p>Answer true if this translator applies to the given triple pattern.</p>
155: * @param pattern An incoming patter to match against
156: * @param da The current dig adapter
157: * @param premises An optional Model that is used to convey the statements in the additional
158: * premises to the query
159: * @return True if this translator applies to the pattern.
160: */
161: public boolean trigger(TriplePattern pattern, DIGAdapter da,
162: Model premises) {
163: return trigger(m_subject, pattern.getSubject(), premises)
164: && trigger(m_object, pattern.getObject(), premises)
165: && trigger(m_pred, pattern.getPredicate(), premises)
166: && checkTriple(pattern, da, premises);
167: }
168:
169: /**
170: * <p>An optional post-trigger check on the consituents of the triple pattern. By default,
171: * delegates to a check on each of the subjec, object and predicate. However, this method
172: * may be overridden by sub-classes to provide a more context-sensitive test.</p>
173: * @param pattern The triple pattern
174: * @param da The current dig adapter
175: * @param premises Model denoting premises to the query, or null
176: * @return True if the pattern conforms to the prerequisites for a given translation step
177: */
178: public boolean checkTriple(TriplePattern pattern, DIGAdapter da,
179: Model premises) {
180: return checkSubject(pattern.getSubject(), da, premises)
181: && checkObject(pattern.getObject(), da, premises)
182: && checkPredicate(pattern.getPredicate(), da, premises);
183:
184: }
185:
186: /**
187: * <p>Additional test on the subject of the incoming find pattern. Default
188: * is to always match</p>
189: * @param subject The subject resource from the incoming pattern
190: * @param da The current dig adapter
191: * @param premises A model that conveys additional information about the premises
192: * of the query, which might assist the check to suceed or fail. By default it
193: * is ignored.
194: * @return True if this subject matches the trigger condition expressed by this translator instance
195: */
196: public boolean checkSubject(Node subject, DIGAdapter da,
197: Model premises) {
198: return true;
199: }
200:
201: /**
202: * <p>Additional test on the object of the incoming find pattern. Default
203: * is to always match</p>
204: * @param object The object resource from the incoming pattern
205: * @param da The current dig adapter
206: * @param premises A model that conveys additional information about the premises
207: * of the query, which might assist the check to suceed or fail. By default it
208: * is ignored.
209: * @return True if this object matches the trigger condition expressed by this translator instance
210: */
211: public boolean checkObject(Node object, DIGAdapter da,
212: Model premises) {
213: return true;
214: }
215:
216: /**
217: * <p>Additional test on the predicate of the incoming find pattern. Default
218: * is to always match</p>
219: * @param pred The predicate resource from the incoming pattern
220: * @param da The current dig adapter
221: * @param premises A model that conveys additional information about the premises
222: * of the query, which might assist the check to suceed or fail. By default it
223: * is ignored.
224: * @return True if this predicate matches the trigger condition expressed by this translator instance
225: */
226: public boolean checkPredicate(Node pred, DIGAdapter da,
227: Model premises) {
228: return true;
229: }
230:
231: /**
232: * <p>Answer an XML document that presents the translation of the query into DIG query language.</p>
233: */
234: public abstract Document translatePattern(TriplePattern query,
235: DIGAdapter da);
236:
237: /**
238: * <p>Answer an XML document that presents the translation of the query into DIG query language,
239: * given that either the subject or object may be expressions defined by the statements
240: * in the premises model.</p>
241: */
242: public abstract Document translatePattern(TriplePattern pattern,
243: DIGAdapter da, Model premises);
244:
245: /**
246: * <p>Answer an extended iterator over the triples that result from translatig the given DIG response
247: * to RDF.</p>
248: */
249: public final ExtendedIterator translateResponse(Document response,
250: TriplePattern query, DIGAdapter da) {
251: ExtendedIterator i = translateResponseHook(response, query, da);
252: Filter f = getResultsTripleFilter(query);
253: return (f == null) ? i : i.filterKeep(f);
254: }
255:
256: // Internal implementation methods
257: //////////////////////////////////
258:
259: /**
260: * <p>Answer an extended iterator over the triples that result from translatig the given DIG response
261: * to RDF.</p>
262: */
263: protected abstract ExtendedIterator translateResponseHook(
264: Document response, TriplePattern query, DIGAdapter da);
265:
266: /**
267: * <p>Answer a node corresponding to the given URI.</p>
268: * @param uri A node URI, or the special string *, or null.
269: * @return A Jena Node corresponding to the given URI
270: */
271: protected Node mapNode(String uri) {
272: if (uri == null) {
273: return null;
274: } else {
275: return (uri.equals(ALL)) ? Node_RuleVariable.WILD : Node
276: .createURI(uri);
277: }
278: }
279:
280: /**
281: * <p>A node matches a trigger (lhs) node if either the lhs is null, or
282: * the nodes are equal. Note: not matching in the same sense as triple patterns.</p>
283: * @param lhs The trigger node to match against
284: * @param rhs The incoming pattern node
285: * @param premises A model that conveys additional information about the premises
286: * of the query, which might assist the trigger to suceed or fail. By default it
287: * is ignored.
288: * @return True if match
289: */
290: protected boolean trigger(Node lhs, Node rhs, Model premises) {
291: return (lhs == null) || lhs.equals(rhs);
292: }
293:
294: /**
295: * <p>Answer true if the given document is the response <true> from a DIG reasoner.
296: * @param response The document encoding the response
297: * @return True iff this is the response <code>true</code>.
298: */
299: protected boolean isTrue(Document response) {
300: return new SimpleXMLPath(true).appendElementPath(
301: DIGProfile.TRUE).getAll(response).hasNext();
302: }
303:
304: /**
305: * <p>Answer true if the given document is the response <false> from a DIG reasoner.
306: * @param response The document encoding the response
307: * @return True iff this is the response <code>false</code>.
308: */
309: protected boolean isFalse(Document response) {
310: return new SimpleXMLPath(true).appendElementPath(
311: DIGProfile.FALSE).getAll(response).hasNext();
312: }
313:
314: /**
315: * <p>Translate a concept set document into an extended iterator
316: * of triples, placing the concept identities into either the subject
317: * or object position in the returned triple.</p>
318: * @param response The response XML document
319: * @param query The original query
320: * @param object Flag to indicate that the concept names should occupy the subject field
321: * of the returned triple, otherwise the object
322: */
323: protected ExtendedIterator translateConceptSetResponse(
324: Document response, TriplePattern query, boolean object,
325: DIGAdapter da) {
326: return translateNameSetResponse(
327: response,
328: query,
329: object,
330: new String[] { DIGProfile.CONCEPT_SET,
331: DIGProfile.SYNONYMS, DIGProfile.CATOM })
332: .andThen(
333: translateSpecialConcepts(response, da,
334: object ? query.getSubject() : query
335: .getObject(), query
336: .getPredicate(), object));
337: }
338:
339: /**
340: * <p>Translate a role set document into an extended iterator
341: * of triples, placing the concept identities into either the subject
342: * or object position in the returned triple.</p>
343: * @param response The response XML document
344: * @param query The original query
345: * @param object Flag to indicate that the role names should occupy the subject field
346: * of the returned triple, or the object
347: */
348: protected ExtendedIterator translateRoleSetResponse(
349: Document response, TriplePattern query, boolean object) {
350: return translateNameSetResponse(response, query, object,
351: new String[] { DIGProfile.ROLE_SET,
352: DIGProfile.SYNONYMS, DIGProfile.RATOM });
353: }
354:
355: /**
356: * <p>Translate an instance set document into an extended iterator
357: * of triples, placing the concept identities into either the subject
358: * or object position in the returned triple.</p>
359: * @param response The response XML document
360: * @param query The original query
361: * @param object Flag to indicate that the instance names should occupy the subject field
362: * of the returned triple, or the object
363: */
364: protected ExtendedIterator translateIndividualSetResponse(
365: Document response, TriplePattern query, boolean object) {
366: return translateNameSetResponse(response, query, object,
367: new String[] { DIGProfile.INDIVIDUAL_SET,
368: DIGProfile.INDIVIDUAL });
369: }
370:
371: /**
372: * <p>Translate an individualPairSet response, which lists pairs of related
373: * individuals for some queried relation p.</p>
374: * @param response
375: * @param query
376: * @return An iterator over triples formed from the result pairs and the known query predicate
377: */
378: protected ExtendedIterator translateIndividualPairSetResponse(
379: Document response, TriplePattern query) {
380: // evaluate a path through the return value to give us an iterator over individual names
381: SimpleXMLPath p = new SimpleXMLPath(true);
382: p.appendElementPath(DIGProfile.INDIVIDUAL_PAIR_SET);
383: p.appendElementPath(DIGProfile.INDIVIDUAL_PAIR);
384: p.appendElementPath(DIGProfile.INDIVIDUAL);
385: p.appendAttrPath(DIGProfile.NAME);
386:
387: // collect the triples corresponding to pairs of results
388: List results = new ArrayList();
389: Node pred = query.getPredicate();
390: DIGValueToNodeMapper dvm = new DIGValueToNodeMapper();
391:
392: // build triples from pairs of results from the XML path iterator
393: Iterator i = p.getAll(response);
394: while (i.hasNext()) {
395: results.add(new Triple(dvm.mapToNode(i.next()), pred, dvm
396: .mapToNode(i.next())));
397: }
398:
399: return WrappedIterator.create(results.iterator());
400: }
401:
402: /**
403: * <p>Translate an document encoding a set of named entities into an extended iterator
404: * of triples, placing the concept identities into either the subject
405: * or object position in the returned triple.</p>
406: * @param response The response XML document
407: * @param query The original query
408: * @param object Flag to indicate that the instance names should occupy the subject field
409: * of the returned triple, or the object
410: * @param path The element name path to follow from the root
411: */
412: protected ExtendedIterator translateNameSetResponse(
413: Document response, TriplePattern query, boolean object,
414: String[] path) {
415: // evaluate a path through the return value to give us an iterator over catom names
416: SimpleXMLPath p = new SimpleXMLPath(true);
417:
418: // build the path
419: for (int i = 0; i < path.length; i++) {
420: p.appendElementPath(path[i]);
421: }
422: p.appendAttrPath(DIGProfile.NAME);
423:
424: // and evaluate it
425: ExtendedIterator iNodes = p.getAll(response).mapWith(
426: new DIGValueToNodeMapper());
427:
428: // return the results as triples
429: if (object) {
430: return iNodes.mapWith(new TripleObjectFiller(query
431: .getSubject(), query.getPredicate()));
432: } else {
433: return iNodes.mapWith(new TripleSubjectFiller(query
434: .getPredicate(), query.getObject()));
435: }
436: }
437:
438: /**
439: * <p>Check if a document representing a concept-set response from the DIG reasoner
440: * contains a given node as a value, and, if so, return a singleton iterator over the
441: * given result triple.</p>
442: * @param response The XML document to process
443: * @param da The DIG adapter
444: * @param node The node we are seeking
445: * @param result The triple to return if node occurs in the concept set in response
446: * @return The singeleton iterator over result, or the null iterator if node is not present
447: * in the response.
448: */
449: protected ExtendedIterator conceptSetNameCheck(Document response,
450: DIGAdapter da, Node node, Triple result) {
451: // evaluate a path through the return value to give us an iterator over catom names
452: ExtendedIterator catoms = new SimpleXMLPath(true)
453: .appendElementPath(DIGProfile.CONCEPT_SET)
454: .appendElementPath(DIGProfile.SYNONYMS)
455: .appendElementPath(SimpleXMLPathElement.ALL_CHILDREN)
456: .getAll(response);
457:
458: // search for the object name
459: String oName = da.getNodeID(node);
460:
461: boolean seekingTop = oName.equals(da.getOntLanguage().THING()
462: .getURI());
463: boolean seekingBottom = oName.equals(da.getOntLanguage()
464: .NOTHING().getURI());
465:
466: boolean found = false;
467: while (!found && catoms.hasNext()) {
468: Element name = (Element) catoms.next();
469:
470: found = (seekingTop && name.getNodeName().equals(
471: DIGProfile.TOP))
472: || (seekingBottom && name.getNodeName().equals(
473: DIGProfile.BOTTOM))
474: || name.getAttribute(DIGProfile.NAME).equals(oName);
475: }
476:
477: // the resulting iterator is either of length 0 or 1
478: return found ? (ExtendedIterator) new SingletonIterator(result)
479: : NullIterator.instance;
480: }
481:
482: /**
483: * <p>Answer an iterator that contains appropriate triples if the given
484: * response contains either top or bottom elements.</p>
485: * @param response The XML document to process
486: * @param da The DIG adapter
487: * @param ref The fixed node in the triple
488: * @param pred The predicate in the triple
489: * @param refSubject True if the reference node is to be the subject of any
490: * created triples
491: * @return An iterator over any subset of Thing and Nothing, if either
492: * or both of top and bottom appear as elements in the response document.
493: */
494: protected ExtendedIterator translateSpecialConcepts(
495: Document response, DIGAdapter da, Node ref, Node pred,
496: boolean refSubject) {
497: SimpleXMLPath topPath = new SimpleXMLPath(true)
498: .appendElementPath(DIGProfile.CONCEPT_SET)
499: .appendElementPath(DIGProfile.SYNONYMS)
500: .appendElementPath(DIGProfile.TOP);
501: SimpleXMLPath bottomPath = new SimpleXMLPath(true)
502: .appendElementPath(DIGProfile.CONCEPT_SET)
503: .appendElementPath(DIGProfile.SYNONYMS)
504: .appendElementPath(DIGProfile.BOTTOM);
505:
506: List specials = new ArrayList();
507:
508: if (topPath.getAll(response).hasNext()) {
509: // the returned concepts include <top/>
510: Node n = da.getOntLanguage().THING().asNode();
511: specials.add(refSubject ? new Triple(ref, pred, n)
512: : new Triple(n, pred, ref));
513:
514: }
515: if (bottomPath.getAll(response).hasNext()) {
516: // the returned concepts include <bottom/>
517: Node n = da.getOntLanguage().NOTHING().asNode();
518: specials.add(refSubject ? new Triple(ref, pred, n)
519: : new Triple(n, pred, ref));
520:
521: }
522:
523: return WrappedIterator.create(specials.iterator());
524: }
525:
526: /**
527: * <p>Extension point: translators can add an optional filter stage to
528: * the translated result by providing a non-null filter here. The filter
529: * should accept triples, and return true for those triples that are to
530: * remain in the final result iterator.</p>
531: * @return An optional filter on the results of a DIG query
532: */
533: protected Filter getResultsTripleFilter(TriplePattern query) {
534: return null;
535: }
536:
537: //==============================================================================
538: // Inner class definitions
539: //==============================================================================
540:
541: }
542:
543: /*
544: * (c) Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
545: * All rights reserved.
546: *
547: * Redistribution and use in source and binary forms, with or without
548: * modification, are permitted provided that the following conditions
549: * are met:
550: * 1. Redistributions of source code must retain the above copyright
551: * notice, this list of conditions and the following disclaimer.
552: * 2. Redistributions in binary form must reproduce the above copyright
553: * notice, this list of conditions and the following disclaimer in the
554: * documentation and/or other materials provided with the distribution.
555: * 3. The name of the author may not be used to endorse or promote products
556: * derived from this software without specific prior written permission.
557: *
558: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
559: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
560: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
561: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
562: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
563: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
564: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
565: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
566: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
567: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
568: */
|