KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > hp > hpl > jena > reasoner > dig > DIGAdapter


1 /*****************************************************************************
2  * Source code information
3  * -----------------------
4  * Original author Ian Dickinson, HP Labs Bristol
5  * Author email ian.dickinson@hp.com
6  * Package Jena 2
7  * Web http://sourceforge.net/projects/jena/
8  * Created 11-Sep-2003
9  * Filename $RCSfile: DIGAdapter.java,v $
10  * Revision $Revision: 1.20 $
11  * Release status $State: Exp $
12  *
13  * Last modified on $Date: 2005/03/16 18:52:27 $
14  * by $Author: ian_dickinson $
15  *
16  * (c) Copyright 2001, 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
17  * [See end of file]
18  *****************************************************************************/

19
20 // Package
21
///////////////
22
package com.hp.hpl.jena.reasoner.dig;
23
24
25
26 // Imports
27
///////////////
28
import java.util.*;
29
30 import com.hp.hpl.jena.datatypes.*;
31 import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
32 import com.hp.hpl.jena.graph.Graph;
33 import com.hp.hpl.jena.ontology.*;
34 import com.hp.hpl.jena.rdf.model.*;
35 import com.hp.hpl.jena.reasoner.TriplePattern;
36 import com.hp.hpl.jena.util.iterator.*;
37 import com.hp.hpl.jena.util.iterator.ExtendedIterator;
38 import com.hp.hpl.jena.util.xml.SimpleXMLPath;
39 import com.hp.hpl.jena.vocabulary.*;
40
41 import org.apache.commons.logging.LogFactory;
42 import org.w3c.dom.*;
43
44
45 /**
46  * <p>
47  * An adapter class that mediates between a Jena InfGraph and a DIG reasoner process.
48  * </p>
49  *
50  * @author Ian Dickinson, HP Labs
51  * (<a HREF="mailto:Ian.Dickinson@hp.com" >email</a>)
52  * @version CVS $Id: DIGAdapter.java,v 1.20 2005/03/16 18:52:27 ian_dickinson Exp $
53  */

54 public class DIGAdapter
55 {
56     // Constants
57
//////////////////////////////////
58

59     /** DIG profile for 1.7 */
60     public static final DIGProfile RACER_17_PROFILE = new DIGProfile() {
61         public String JavaDoc getDIGNamespace() {return "http://dl.kr.org/dig/lang"; }
62         public String JavaDoc getSchemaLocation() {return "http://potato.cs.man.ac.uk/dig/level0/dig.xsd"; }
63         public String JavaDoc getContentType() {return "application/x-www-form-urlencoded";}
64     };
65
66     // switch codes for expression types
67
private static final int UNION = 1;
68     private static final int INTERSECTION = 2;
69     private static final int COMPLEMENT = 3;
70     private static final int ENUMERATED = 4;
71     private static final int RESTRICTION = 5;
72
73     /** Mark a bNode identifier */
74     public static final String JavaDoc ANON_MARKER = "anon:";
75
76     /** Well known concept URI's */
77     public static final List KNOWN_CONCEPTS = Arrays.asList( new Object JavaDoc[] {OWL.Thing.getURI(), OWL.Nothing.getURI(),
78                                                                            DAML_OIL.Thing.getURI(), DAML_OIL.Thing.getURI() } );
79
80     /** Well known integer type URI's, these we will translate into DIG integer attributes */
81     public static final List XSD_INT_TYPES = Arrays.asList( new Object JavaDoc[] {
82             XSDDatatype.XSDint.getURI(),
83             XSDDatatype.XSDinteger.getURI(),
84             XSDDatatype.XSDnonNegativeInteger.getURI(),
85             XSDDatatype.XSDbyte.getURI(),
86             XSDDatatype.XSDshort.getURI(),
87             XSDDatatype.XSDlong.getURI(),
88             XSDDatatype.XSDunsignedByte.getURI(),
89             XSDDatatype.XSDunsignedLong.getURI(),
90             XSDDatatype.XSDunsignedInt.getURI(),
91             XSDDatatype.XSDunsignedShort.getURI(),
92     } );
93
94
95     // Static variables
96
//////////////////////////////////
97

98     /** Query ID counter */
99     private static int s_queryID = 0;
100
101     /** The table that represents the query translations we know about */
102     protected static DIGQueryTranslator[] s_queryTable = {
103         // subsumes when testing for subsumption between two known class expressions
104
new DIGQuerySubsumesTranslator( RDFS.subClassOf.getURI() ),
105         new DIGQuerySubsumesTranslator( DAML_OIL.subClassOf.getURI() ),
106
107         // testing for disjoint between two known class expressions
108
new DIGQueryDisjointTranslator( OWL.disjointWith.getURI() ),
109         new DIGQueryDisjointTranslator( DAML_OIL.disjointWith.getURI() ),
110
111         // ancestors and parents when testing for a named and variable node
112
new DIGQueryAncestorsTranslator( RDFS.subClassOf.getURI(), true ),
113         new DIGQueryAncestorsTranslator( RDFS.subClassOf.getURI(), false ),
114         new DIGQueryAncestorsTranslator( DAML_OIL.subClassOf.getURI(), true ),
115         new DIGQueryAncestorsTranslator( DAML_OIL.subClassOf.getURI(), false ),
116
117         // all parents and all children
118
new DIGQueryParentsTranslator( ReasonerVocabulary.directSubClassOf.getURI(), true ),
119         new DIGQueryParentsTranslator( ReasonerVocabulary.directSubClassOf.getURI(), false ),
120
121         // specific named parent or child
122
new DIGQueryParentsTranslator( null, ReasonerVocabulary.directSubClassOf.getURI(), null, true ),
123         new DIGQueryParentsTranslator( null, ReasonerVocabulary.directSubClassOf.getURI(), null, false ),
124
125         // the entire class hierarchy
126
new DIGQueryClassHierarchyTranslator( RDFS.subClassOf.getURI() ),
127         new DIGQueryClassHierarchyTranslator( DAML_OIL.subClassOf.getURI() ),
128
129         // equivalent classes
130
new DIGQueryEquivalentsTranslator( OWL.equivalentClass.getURI(), true ),
131         new DIGQueryEquivalentsTranslator( OWL.equivalentClass.getURI(), false ),
132         new DIGQueryEquivalentsTranslator( DAML_OIL.sameClassAs.getURI(), true ),
133         new DIGQueryEquivalentsTranslator( DAML_OIL.sameClassAs.getURI(), false ),
134
135         new DIGQueryIsEquivalentTranslator( OWL.equivalentClass.getURI() ),
136         new DIGQueryIsEquivalentTranslator( DAML_OIL.sameClassAs.getURI() ),
137
138         // rancestors and rparents when testing for a named and variable node
139
new DIGQueryRoleAncestorsTranslator( RDFS.subPropertyOf.getURI(), true ),
140         new DIGQueryRoleAncestorsTranslator( RDFS.subPropertyOf.getURI(), false ),
141         new DIGQueryRoleAncestorsTranslator( DAML_OIL.subPropertyOf.getURI(), true ),
142         new DIGQueryRoleAncestorsTranslator( DAML_OIL.subPropertyOf.getURI(), false ),
143
144         new DIGQueryRoleParentsTranslator( ReasonerVocabulary.directSubPropertyOf.getURI(), true ),
145         new DIGQueryRoleParentsTranslator( ReasonerVocabulary.directSubPropertyOf.getURI(), false ),
146
147         // the entire role hierarchy
148
new DIGQueryRoleHierarchyTranslator( RDFS.subPropertyOf.getURI() ),
149         new DIGQueryRoleHierarchyTranslator( DAML_OIL.subPropertyOf.getURI() ),
150
151         // all concepts query for [* rdf:type :Class]
152
new DIGQueryAllConceptsTranslator( RDF.type.getURI(), RDFS.Class.getURI() ),
153         new DIGQueryAllConceptsTranslator( RDF.type.getURI(), OWL.Class.getURI() ),
154         new DIGQueryAllConceptsTranslator( RDF.type.getURI(), DAML_OIL.Class.getURI() ),
155
156         // instances
157
new DIGQueryInstancesTranslator( RDF.type.getURI() ),
158         new DIGQueryInstancesTranslator( DAML_OIL.type.getURI() ),
159         new DIGQueryTypesTranslator( RDF.type.getURI() ),
160         new DIGQueryTypesTranslator( DAML_OIL.type.getURI() ),
161         new DIGQueryInstanceTranslator( RDF.type.getURI() ),
162         new DIGQueryInstanceTranslator( DAML_OIL.type.getURI() ),
163         new DIGQueryDifferentFromTranslator( OWL.differentFrom.getURI() ),
164         new DIGQueryDifferentFromTranslator( DAML_OIL.differentIndividualFrom.getURI() ),
165         new DIGQueryRoleFillersTranslator(),
166         new DIGQueryRoleFillerTranslator(),
167
168         // specific type tests
169
new DIGQueryIsConceptTranslator(),
170         new DIGQueryIsRoleTranslator(),
171         new DIGQueryIsIndividualTranslator(),
172     };
173
174
175     // Instance variables
176
//////////////////////////////////
177

178     /** The profile for the DIG interface this reasoner is interacting with. Defaults to Racer 1.7 */
179     protected DIGProfile m_profile = RACER_17_PROFILE;
180
181     /** The graph that contains the data we are uploading to the external DIG reasoner */
182     protected OntModel m_sourceData;
183
184     /** Counter for generating skolem names */
185     private int m_skolemCounter = 0;
186
187     /** The connection to the DIG reasoner */
188     private DIGConnection m_connection;
189
190     /** The set of known individual names from the DIG reasoner */
191     protected Set m_indNames = new HashSet();
192
193     /** Flag that is set to true once we have asked the remote reasoner for its list of individual names */
194     protected boolean m_indNamesAsked = false;
195
196     /** The set of known concept names from the DIG reasoner */
197     protected Set m_conceptNames = new HashSet();
198
199     /** Flag that is set to true once we have asked the remote reasoner for its list of concept names */
200     protected boolean m_conceptNamesAsked = false;
201
202     /** The set of known role names from the DIG reasoner */
203     protected Set m_roleNames = new HashSet();
204
205     /** Flag that is set to true once we have asked the remote reasoner for its list of role names */
206     protected boolean m_roleNamesAsked = false;
207
208     /** Model containing axiom statements */
209     protected Model m_axioms = null;
210
211
212     // Constructors
213
//////////////////////////////////
214

215     /**
216      * <p>Construct a DIG adapter for the given source data graph, which is encoding an
217      * ontology in a language represented by the given model spec. Allocates a new
218      * DIG connection using the default connection URL (<code>http://localhost:8081</code>).</p>
219      * @param spec An ont model spec encoding the ontology language of the source graph
220      * @param source The graph that contains the source data on which the DIG reasoner
221      * will operate
222      */

223     public DIGAdapter( OntModelSpec spec, Graph source ) {
224         this( spec, source, DIGConnectionPool.getInstance().allocate(), null );
225     }
226
227
228     /**
229      * <p>Construct a DIG adapter for the given source data graph, which is encoding an
230      * ontology in a language represented by the given model spec.</p>
231      * @param spec An ont model spec encoding the ontology language of the source graph
232      * @param source The graph that contains the source data on which the DIG reasoner
233      * will operate
234      * @param connection A pre-configured DIG connection to use to communicate with the
235      * external reasoner
236      * @param axioms A model containing axioms appropriate to the ontology language
237      * this adapter is processing. May be null.
238      */

239     public DIGAdapter( OntModelSpec spec, Graph source, DIGConnection connection, Model axioms ) {
240         m_connection = connection;
241         m_axioms = axioms;
242
243         // we wrap the given graph in a suitable ontology model
244
m_sourceData = ModelFactory.createOntologyModel( spec, ModelFactory.createModelForGraph( source ) );
245
246         // don't do the .as() checking, since we know we're not using the reasoner
247
m_sourceData.setStrictMode( false );
248     }
249
250
251     // External signature methods
252
//////////////////////////////////
253

254     /**
255      * <p>Answer the DIG profile for the DIG interface this reasoner is attached to.</p>
256      * @return A profile detailing the parameters of the DIG variant this reasoner is interacting with.
257      */

258     public DIGProfile getProfile() {
259         return m_profile;
260     }
261
262
263     /**
264      * <p>Set the profile specifying the variable parts of the DIG profile that are being
265      * used in this instance.</p>
266      * @param profile The new DIG profile
267      */

268     public void setProfile( DIGProfile profile ) {
269         m_profile = profile;
270     }
271
272
273     /**
274      * <p>Answer the ontology language profile we're assuming in this reasoner.</p>
275      * @return The ontology language via the language profile
276      */

277     public Profile getOntLanguage() {
278         return m_sourceData.getProfile();
279     }
280
281
282     /**
283      * <p>Answer the DIG identification structure we obtain by querying the attached reasoner.</p>
284      * @return An object containing the results of querying the reasoner for its identity
285      * and capabilities
286      */

287     public DIGIdentifier getDigIdentifier() {
288         Document getIDVerb = getConnection().createDigVerb( DIGProfile.GET_IDENTIFIER, getProfile() );
289         return new DigIdentifierImpl( getConnection().sendDigVerb( getIDVerb, getProfile() ) );
290     }
291
292
293     /**
294      * <p>Upload the entire contents of the local knowledge base (OWL/DAML model)
295      * to the DIG reasoner, using a single large TELL verb.</p>
296      * @return True if the ontology model was uploaded to DIG without any warnings. Recent warnings
297      * are available via {@link #getRecentWarnings}
298      * @exception DigReasonerException If the upload fails for any reason. The error message from
299      * the DIG reasoner will be returned.
300      */

301     public boolean uploadKB() {
302         // ensure first that we have a KB identifier
303
getConnection().bindKB( false, getProfile() );
304
305         // now tell the existing KB contents
306
Document kbDIG = translateKbToDig();
307
308         Document response = getConnection().sendDigVerb( kbDIG, getProfile() );
309         return !getConnection().warningCheck( response );
310     }
311
312
313
314     /**
315      * <p>Answer an iterator over any recent warnings returned from from the remote DIG reasoner.</p>
316      * @return An iterator over any warnings; if there are no warnings the return
317      * value will be an iterator that returns <code>hasNext()</code> = false.
318      */

319     public Iterator getRecentWarnings() {
320         return getConnection().getWarnings();
321     }
322
323
324     /**
325      * <p>Answer an XML document that contains the DIG translation of the local graph, wrapped
326      * as a tell verb</p>
327      * @return An XML document containing the tell verb
328      */

329     public Document translateKbToDig() {
330         Document tell = getConnection().createDigVerb( DIGProfile.TELLS, getProfile() );
331         Element root = tell.getDocumentElement();
332
333         addNamedEntities( root );
334         translateClasses( root );
335         translateRoles( root );
336         translateAttributes( root );
337         translateIndividuals( root );
338         translateAllDifferentAxioms( root );
339
340         return tell;
341     }
342
343
344     /**
345      * <p>Clear the old contents of the DIG knowledge base</p>
346      */

347     public void resetKB() {
348         getConnection().bindKB( true, getProfile() );
349
350         // reset the name caches
351
m_indNames.clear();
352         m_indNamesAsked = false;
353         m_conceptNames.clear();
354         m_conceptNamesAsked = false;
355         m_roleNames.clear();
356         m_roleNamesAsked = false;
357     }
358
359
360     /**
361      * <p>Answer this adapter's connection to the database.</p>
362      * @return The DIG connector this adapter is using, or null if the connection has
363      * been closed.
364      */

365     public DIGConnection getConnection() {
366         return m_connection;
367     }
368
369
370     /**
371      * <p>Close this adapter, and release the connector to the external DIG KB.</p>
372      */

373     public void close() {
374         getConnection().release();
375         m_connection = null;
376     }
377
378
379     /**
380      * <p>Basic pattern lookup interface - answer an iterator over the triples
381      * matching the given pattern. Where possible, this query will first be
382      * given to the external reasoner, with the local graph used to generate
383      * supplemental bindings.</p>
384      * @param pattern a TriplePattern to be matched against the data
385      * @return An ExtendedIterator over all Triples in the data set
386      * that match the pattern
387      */

388     public ExtendedIterator find( TriplePattern pattern ) {
389         DIGQueryTranslator tr = getQueryTranslator( pattern, null );
390
391         ExtendedIterator remote = (tr == null) ? null : tr.find( pattern, this );
392
393         com.hp.hpl.jena.graph.Node pSubj = normaliseNode( pattern.getSubject() );
394         com.hp.hpl.jena.graph.Node pPred = normaliseNode( pattern.getPredicate() );
395         com.hp.hpl.jena.graph.Node pObj = normaliseNode( pattern.getObject() );
396         ExtendedIterator local = m_sourceData.getGraph().find( pSubj, pPred, pObj );
397
398         // if we have a remote iterator, prepend to the local one and drop duplicates
399
ExtendedIterator i = (remote == null) ? local : remote.andThen( local );
400
401         // add the axioms if specified
402
i = (m_axioms == null) ? i : i.andThen( m_axioms.getGraph().find( pSubj, pPred, pObj ) );
403
404         // make sure we don't have duplicates
405
return UniqueExtendedIterator.create( i );
406     }
407
408
409     /**
410      * <p>Basic pattern lookup interface - answer an iterator over the triples
411      * matching the given (S,P,O) pattern, given also some premises for the
412      * query. Where possible, this query will first be
413      * given to the external reasoner, with the local graph used to generate
414      * supplemental bindings.</p>
415      * @param pattern a TriplePattern to be matched against the data
416      * @param premises A model containing additional premises for the find query,
417      * typically used to allow the subject and/or object to be an expression
418      * rather than just a simple node
419      * @return An ExtendedIterator over all Triples in the data set
420      * that match the pattern
421      */

422     public ExtendedIterator find( TriplePattern pattern, Model premises ) {
423         DIGQueryTranslator tr = getQueryTranslator( pattern, premises );
424
425         if (tr == null) {
426             LogFactory.getLog( getClass() ).debug( "Could not find DIG query translator for " + pattern );
427         }
428
429         ExtendedIterator remote = (tr == null) ? null : tr.find( pattern, this, premises );
430
431         com.hp.hpl.jena.graph.Node pSubj = normaliseNode( pattern.getSubject() );
432         com.hp.hpl.jena.graph.Node pPred = normaliseNode( pattern.getPredicate() );
433         com.hp.hpl.jena.graph.Node pObj = normaliseNode( pattern.getObject() );
434         ExtendedIterator local = m_sourceData.getGraph().find( pSubj, pPred, pObj );
435
436         // if we have a remote iterator, prepend to the local one and drop duplicates
437
ExtendedIterator i = (remote == null) ? local : remote.andThen( local );
438
439         // add the axioms if specified
440
i = (m_axioms == null) ? i : i.andThen( m_axioms.getGraph().find( pSubj, pPred, pObj ) );
441
442         // make sure we don't have duplicates
443
return UniqueExtendedIterator.create( i );
444     }
445
446
447     /**
448      * <p>Answer the query translator that matches the given pattern, if any</p>
449      * @param pattern The triple pattern that has been received
450      * @param premises A model containing the premises to a query (e.g. a class expression)
451      * @return A DIG translator that can translate this pattern to a DIG query,
452      * or null if no matches.
453      */

454     public DIGQueryTranslator getQueryTranslator( TriplePattern pattern, Model premises ) {
455         for (int i = 0; i < s_queryTable.length; i++) {
456             DIGQueryTranslator dqt = s_queryTable[i];
457
458             if (s_queryTable[i].trigger( pattern, this, premises )) {
459                 return s_queryTable[i];
460             }
461         }
462
463         return null;
464     }
465
466
467     /**
468      * <p>Answer the graph of local (source) data.</p>
469      * @return The graph containing the local source data.
470      */

471     public Graph getGraph() {
472         return m_sourceData.getGraph();
473     }
474
475
476     /**
477      * <p>Answer an identifier for a resource, named or bNode</p>
478      * @param r A resource
479      * @return A unique identifier for the resource as a string, which will either
480      * be the resource URI for named resources, or a unique ID string for bNodes
481      */

482     public String JavaDoc getResourceID( Resource r ) {
483         return getNodeID( r.asNode() );
484     }
485
486
487     /**
488      * <p>Answer an identifier for a node, named or anon</p>
489      * @param n An RDF node
490      * @return A unique identifier for the node as a string, which will either
491      * be the resource URI for named nodes, or a unique ID string for bNodes
492      */

493     public String JavaDoc getNodeID( com.hp.hpl.jena.graph.Node n ) {
494         if (n.isBlank()) {
495             return ANON_MARKER + n.getBlankNodeId().toString();
496         }
497         else {
498             return n.getURI();
499         }
500     }
501
502
503     /**
504      * <p>Add a DIG reference to the class identifed in the source graph by the given Jena
505      * graph Node to the given XML element. If the class is a named class, this will be
506      * a <code>&lt;catom&gt;</code> element, otherwise it will be a class description axiom.
507      * Assumes that the instance variable <code>m_sourceData</code> provides the statements that
508      * further define the class if it is a description not a name.
509      * </p>
510      * @param elem The parent XML element to which the class description will be attached
511      * @param node An RDF graph node representing a class we wish to describe.
512      */

513     public void addClassDescription( Element elem, com.hp.hpl.jena.graph.Node node ) {
514         addClassDescription( elem, node, m_sourceData );
515     }
516
517
518     /**
519      * <p>Add a DIG reference to the class identifed in the source graph by the given Jena
520      * graph Node to the given XML element. If the class is a named class, this will be
521      * a <code>&lt;catom&gt;</code> element, otherwise it will be a class description axiom.
522      * </p>
523      * @param elem The parent XML element to which the class description will be attached
524      * @param node An RDF graph node representing a class we wish to describe.
525      * @param sourceData A model containing the statements about the given class description
526      * resource
527      */

528     public void addClassDescription( Element elem, com.hp.hpl.jena.graph.Node node, Model sourceData ) {
529         Model m = (sourceData == null) ? m_sourceData : sourceData;
530         addClassDescription( elem, (Resource) m.getRDFNode( node ), m );
531     }
532
533
534     /**
535      * <p>Add a DIG reference to the class identifed in the source graph by the given Jena
536      * resource to the given XML element. If the class is a named class, this will be
537      * a <code>&lt;catom&gt;</code> element, otherwise it will be a class description axiom.</p>
538      * @param elem The parent XML element to which the class description will be attached
539      * @param res An RDF resource representing a class we wish to describe.
540      * @param sourceData A model containing the statements about the given class description
541      * resource
542      */

543     public void addClassDescription( Element elem, Resource res, Model sourceData ) {
544         // ensure we have a resource from the source data model
545
Resource cls = (res.getModel() != sourceData) ? sourceData.getResource( res.getURI() ) : res;
546
547         if (!cls.isAnon() || m_conceptNames.contains( getNodeID( cls.getNode() ))) {
548             // a named class, or an already known bNode
549
translateClassIdentifier( elem, cls );
550         }
551         else {
552             // a new bNode introducing a class expression
553
translateClassDescription( elem, (OntClass) cls.as( OntClass.class ), sourceData );
554         }
555     }
556
557
558     /**
559      * <p>Answer true if the given node corresponds to one of the individuals known to
560      * the DIG reasoner.</p>
561      * @param node A node to test
562      * @return True if <code>node</code> is a known individual
563      */

564     public boolean isIndividual( com.hp.hpl.jena.graph.Node node ) {
565         return node.isConcrete() && !node.isLiteral() && getKnownIndividuals().contains( getNodeID( node ) );
566     }
567
568
569     /**
570      * <p>Answer true if the given node corresponds to one of the roles known to
571      * the DIG reasoner.</p>
572      * @param node A node to test
573      * @param premises A model defining premises that may encode more information about
574      * node, or may be null
575      * @return True if <code>node</code> is a known role
576      */

577     public boolean isRole( com.hp.hpl.jena.graph.Node node, Model premises ) {
578         return node.isConcrete() &&
579                (getKnownRoles().contains( getNodeID( node ) ) ||
580                 ((premises != null) &&
581                 isPremisesRole( node, premises )) );
582     }
583
584
585     /**
586      * <p>Answer true if the given node corresponds to one of the concepts known to
587      * the DIG reasoner.</p>
588      * @param node A node to test
589      * @param premises A model defining premises that may encode more information about
590      * node, or may be null
591      * @return True if <code>node</code> is a known concept
592      */

593     public boolean isConcept( com.hp.hpl.jena.graph.Node node, Model premises ) {
594         return node.isConcrete() && !node.isLiteral() &&
595                (getKnownConcepts().contains( getNodeID( node ) ) ||
596                 ((premises != null) && isPremisesClass( node, premises )) ||
597                 KNOWN_CONCEPTS.contains( getNodeID( node ) ));
598     }
599
600
601     /**
602      * <p>Answer the ontology language specification for the source model underlying
603      * this DIG adapter.</p>
604      * @return The ontology model spec
605      */

606     public OntModelSpec getSourceSpecification() {
607         return m_sourceData.getSpecification();
608     }
609
610
611     /**
612      * <p>Create a new element to represent a query, adding to it a unique query
613      * ID.</p>
614      * @param query The query document
615      * @param elemName The string name of the query element
616      * @return The new query element
617      */

618     public Element createQueryElement( Document query, String JavaDoc elemName ) {
619         Element qElem = addElement( query.getDocumentElement(), elemName );
620         qElem.setAttribute( DIGProfile.ID, "q" + s_queryID++ );
621         return qElem;
622     }
623
624
625     // Internal implementation methods
626
//////////////////////////////////
627

628
629     /**
630      * <p>In Dig, defXXX elements are required to introduce all named entities,
631      * such as concepts and roles. This method collects such definitions and
632      * adds the defXXX elements as children of the tell element.</p>
633      * @param tell The XML element, typically &lt;tells&gt;, to which to attach the
634      * declarations
635      */

636     protected void addNamedEntities( Element tell ) {
637         // first we collect the named entities
638
HashSet roles = new HashSet();
639         HashSet attributes = new HashSet();
640         HashSet concepts = new HashSet();
641         HashSet individuals = new HashSet();
642
643         addAll( m_sourceData.listClasses(), concepts );
644         addAll( m_sourceData.listDatatypeProperties(), attributes );
645         addAll( m_sourceData.listIndividuals(), individuals );
646
647         collectRoleProperties( roles );
648
649         // collect the DIG definitions at the beginning of the document
650
addNamedDefs( tell, concepts.iterator(), DIGProfile.DEFCONCEPT, m_conceptNames );
651         addNamedDefs( tell, roles.iterator(), DIGProfile.DEFROLE, m_roleNames );
652         addNamedDefs( tell, attributes.iterator(), DIGProfile.DEFATTRIBUTE, null);
653         addNamedDefs( tell, individuals.iterator(), DIGProfile.DEFINDIVIDUAL, m_indNames );
654     }
655
656
657     /** Add all object properties (roles) to the given collection */
658     protected void collectRoleProperties( Collection roles ) {
659         addAll( m_sourceData.listObjectProperties(), roles );
660         addAll( m_sourceData.listInverseFunctionalProperties(), roles );
661         addAll( m_sourceData.listTransitiveProperties(), roles );
662
663         // not present in DAML
664
if (m_sourceData.getProfile().SYMMETRIC_PROPERTY() != null) {
665             addAll( m_sourceData.listSymmetricProperties(), roles );
666         }
667     }
668
669
670     /**
671      * <p>Add the named definitions from the given iterator to the tell document we are building.</p>
672      * @param tell The document being built
673      * @param i An iterator over resources
674      * @param defType The type of DIG element we want to build
675      * @param nameCollection Optional set of names of this type of entity to collect
676      */

677     protected void addNamedDefs( Element tell, Iterator i, String JavaDoc defType, Set nameCollection ) {
678         while (i.hasNext()) {
679             RDFNode n = (Resource) i.next();
680             if (n instanceof Resource) {
681                 String JavaDoc id = getNodeID( n.asNode() );
682                 addNamedElement( tell, defType, getNodeID( n.asNode() ) );
683
684                 // a named concept, role, etc is being defined
685
if (nameCollection != null) {
686                     nameCollection.add( id );
687                 }
688             }
689         }
690     }
691
692
693     /**
694      * <p>Answer a element with the given element name,
695      * and with a attribute 'name' with the given uri as name.<p>
696      * @param parent The parent node to add to
697      * @param elemName The element name, eg defconcept
698      * @param uri The URI of the definition
699      * @return A named element
700      */

701     protected Element addNamedElement( Element parent, String JavaDoc elemName, String JavaDoc uri ) {
702         Element elem = addElement( parent, elemName );
703         elem.setAttribute( DIGProfile.NAME, uri );
704
705         return elem;
706     }
707
708
709     /** Add to the given element a child element with the given name */
710     protected Element addElement( Element parent, String JavaDoc childName ) {
711         Element child = parent.getOwnerDocument().createElement( childName );
712         return (Element) parent.appendChild( child );
713     }
714
715
716     /** Add iterator contents to collection */
717     private void addAll( Iterator i, Collection c ) {
718         for (; i.hasNext(); c.add( i.next() ) );
719     }
720
721
722     /**
723      * <p>Translate all of the classes in the current KB into descriptions
724      * using the DIG concept language, and attach the axioms generated
725      * to the given element.</p>
726      * @param tell The XML element, typically &lt;tells&gt;, to which
727      * to attach the generated translations.
728      */

729     protected void translateClasses( Element tell ) {
730         translateSubClassAxioms( tell );
731         translateClassEquivalences( tell );
732         translateClassDisjointAxioms( tell );
733
734         translateRestrictions( tell );
735
736         // now the implicit equivalences
737
translateClassExpressions( tell, getOntLanguage().INTERSECTION_OF(), INTERSECTION );
738         translateClassExpressions( tell, getOntLanguage().UNION_OF(), UNION );
739         translateClassExpressions( tell, getOntLanguage().COMPLEMENT_OF(), COMPLEMENT );
740         translateClassExpressions( tell, getOntLanguage().ONE_OF(), ENUMERATED );
741     }
742
743     /**
744      * <p>Translate the sub-class axioms in the source model into DIG
745      * impliesc axioms</p>
746      * @param tell The node representing the DIG tell verb
747      */

748     protected void translateSubClassAxioms( Element tell ) {
749         StmtIterator i = m_sourceData.listStatements( null, getOntLanguage().SUB_CLASS_OF(), (RDFNode) null );
750         while (i.hasNext()) {
751             Statement sc = i.nextStatement();
752             Element impliesc = addElement( tell, DIGProfile.IMPLIESC );
753             addClassDescription( impliesc, sc.getSubject(), m_sourceData );
754             addClassDescription( impliesc, sc.getResource(), m_sourceData );
755         }
756     }
757
758
759     /**
760      * <p>Translate the class equivalence axioms in the source model into DIG
761      * equalsc axioms.</p>
762      * @param tell The node representing the DIG tell verb
763      */

764     protected void translateClassEquivalences( Element tell ) {
765         // first we do stated equivalences
766
StmtIterator i = m_sourceData.listStatements( null, getOntLanguage().EQUIVALENT_CLASS(), (RDFNode) null );
767         while (i.hasNext()) {
768             Statement sc = i.nextStatement();
769             Element equalc = addElement( tell, DIGProfile.EQUALC );
770             addClassDescription( equalc, sc.getSubject(), m_sourceData );
771             addClassDescription( equalc, sc.getResource(), m_sourceData );
772         }
773     }
774
775
776     /**
777      * <p>Translate class expressions, such as union classes, intersection classes, etc, into the DIG.</p>
778      * concept language. The translations are attached to the given tell node.</p>
779      * @param tell The node representing the DIG tell verb
780      * @param p A property that will require an implicit equivalence to be made explicit
781      * in a correct translation to DIG
782      * @param classExprType Denotes the type of class expression we are translating
783      */

784     protected void translateClassExpressions( Element tell, Property p, int classExprType ) {
785         translateClassExpressions( tell, m_sourceData.listStatements( null, p, (RDFNode) null ), classExprType, m_sourceData );
786     }
787
788
789     /**
790      * <p>Translate the restrictions in the source model into the DIG concept language.</p>
791      * @param tell The node representing the DIG tell verb
792      */

793     protected void translateRestrictions( Element tell ) {
794         translateClassExpressions( tell,
795                                    m_sourceData.listStatements( null, RDF.type, getOntLanguage().RESTRICTION() ),
796                                    RESTRICTION, m_sourceData );
797     }
798
799
800     /**
801      * <p>A named owl:class with a class-construction axiom directly attached is implicitly
802      * an equivalence axiom with the anonymous class that has the given class construction.</p>
803      * @param tell The node representing the DIG tell verb
804      * @param i A statement iterator whose subjects denote the class expressions to be translated
805      * @param classExprType Denotes the type of class expression we are translating
806      */

807     protected void translateClassExpressions( Element tell, StmtIterator i, int classExprType, Model source ) {
808         while (i.hasNext()) {
809             OntClass cls = (OntClass) i.nextStatement().getSubject().as( OntClass.class );
810
811             Element equalc = addElement( tell, DIGProfile.EQUALC );
812             addClassDescription( equalc, cls, source );
813
814             switch (classExprType) {
815                 case UNION: translateUnionClass( equalc, cls, source ); break;
816                 case INTERSECTION: translateIntersectionClass( equalc, cls, source ); break;
817                 case COMPLEMENT: translateComplementClass( equalc, cls, source ); break;
818                 case ENUMERATED: translateEnumeratedClass( equalc, cls, source ); break;
819                 case RESTRICTION: translateRestrictionClass( equalc, cls, source ); break;
820             }
821         }
822     }
823
824
825     /**
826      * <p>Translate a node representing a class expression (presumed anonymous, though
827      * this is not tested) into the appropriate DIG class axiom.</p>
828      * @param parent The XML node that will be the parent of the class description axiom
829      * @param classDescr An OntClass representing the class expression to be translated
830      */

831     protected void translateClassDescription( Element parent, OntClass classDescr, Model source ) {
832         if (classDescr.isUnionClass()) {
833             translateUnionClass( parent, classDescr, source );
834         }
835         else if (classDescr.isIntersectionClass()) {
836             translateIntersectionClass( parent, classDescr, source );
837         }
838         else if (classDescr.isComplementClass()) {
839             translateComplementClass( parent, classDescr, source );
840         }
841         else if (classDescr.isEnumeratedClass()) {
842             translateEnumeratedClass( parent, classDescr, source );
843         }
844         else if (classDescr.isRestriction()) {
845             translateRestrictionClass( parent, classDescr, source );
846         }
847     }
848
849
850     /**
851      * <p>Translate any statements from the KB that indicates disjointness between
852      * two classes.</p>
853      * @param tell The XML element representing the tell verb we will attach the
854      * translations to.
855      */

856     protected void translateClassDisjointAxioms( Element tell ) {
857         StmtIterator i = m_sourceData.listStatements( null, getOntLanguage().DISJOINT_WITH(), (RDFNode) null );
858         while (i.hasNext()) {
859             Statement sc = i.nextStatement();
860             Element impliesc = addElement( tell, DIGProfile.DISJOINT );
861             addClassDescription( impliesc, sc.getSubject(), m_sourceData );
862             addClassDescription( impliesc, sc.getResource(), m_sourceData );
863         }
864     }
865
866
867     /**
868      * <p>Translate a given class resource into a DIG concept description, as a child
869      * of the given expression element</p>
870      * @param expr The parent expression element
871      * @param c The concept resource
872      */

873     protected void translateClassIdentifier( Element expr, Resource c ) {
874         if (c.equals( getOntLanguage().THING())) {
875             // this is TOP in DIG
876
addElement( expr, DIGProfile.TOP );
877             return;
878         }
879         else if (c.equals( getOntLanguage().NOTHING())) {
880             // this is BOTTOM in DIG
881
addElement( expr, DIGProfile.BOTTOM );
882             return;
883         }
884         else {
885             // a named class is represented as a catom element
886
Element catom = addElement( expr, DIGProfile.CATOM );
887             String JavaDoc digConceptName = getNodeID( c.asNode() );
888             catom.setAttribute( DIGProfile.NAME, digConceptName );
889         }
890     }
891
892
893     /**
894      * <p>Translate a given restriction resource into a DIG concept description, as a child
895      * of the given expression element</p>
896      * @param expr The parent expression element
897      * @param c The restriction concept resource
898      */

899     protected void translateRestrictionClass( Element expr, Resource c, Model source ) {
900         Restriction r = (Restriction) c.as( Restriction.class );
901
902         if (r.isAllValuesFromRestriction()) {
903             // all values from restriction translates to a DIG <all>R E</all> axiom
904
Element all = addElement( expr, DIGProfile.ALL );
905             addNamedElement( all, DIGProfile.RATOM, r.getOnProperty().getURI() );
906             addClassDescription( all, r.asAllValuesFromRestriction().getAllValuesFrom(), source );
907         }
908         else if (r.isSomeValuesFromRestriction()) {
909             // some values from restriction translates to a DIG <some>R E</some> axiom
910
Element some = addElement( expr, DIGProfile.SOME );
911             addNamedElement( some, DIGProfile.RATOM, r.getOnProperty().getURI() );
912             addClassDescription( some, r.asSomeValuesFromRestriction().getSomeValuesFrom(), source );
913         }
914         else if (r.isHasValueRestriction()) {
915             // special case
916
translateHasValueRestriction( expr, r.asHasValueRestriction() );
917         }
918         else if (r.isMinCardinalityRestriction()) {
919             // unqualified, so we make the qualification class TOP
920
translateCardinalityRestriction( expr, r.asMinCardinalityRestriction().getMinCardinality(), r,
921                                              DIGProfile.ATLEAST, getOntLanguage().THING(), source );
922         }
923         else if (r.isMaxCardinalityRestriction()) {
924             // unqualified, so we make the qualification class TOP
925
translateCardinalityRestriction( expr, r.asMaxCardinalityRestriction().getMaxCardinality(), r,
926                                              DIGProfile.ATMOST, getOntLanguage().THING(), source );
927         }
928         else if (r.isCardinalityRestriction()) {
929             // we model a cardinality restriction as the intersection of min and max resrictions
930
Element and = addElement( expr, DIGProfile.AND );
931
932             // unqualified, so we make the qualification class TOP
933
translateCardinalityRestriction( and, r.asCardinalityRestriction().getCardinality(), r,
934                                              DIGProfile.ATMOST, getOntLanguage().THING(), source );
935             translateCardinalityRestriction( and, r.asCardinalityRestriction().getCardinality(), r,
936                                              DIGProfile.ATLEAST, getOntLanguage().THING(), source );
937         }
938         // TODO qualified cardinality restrictions
939
}
940
941
942     /** Translate an enumerated class to an iset element */
943     protected void translateEnumeratedClass(Element expr, OntClass cls, Model source ) {
944         // an anonymous enumeration of class expressions
945
Element iset = addElement( expr, DIGProfile.ISET );
946         for (Iterator i = cls.asEnumeratedClass().listOneOf(); i.hasNext(); ) {
947             RDFNode n = (RDFNode) i.next();
948
949             if (n instanceof Resource) {
950                 addNamedElement( iset, DIGProfile.INDIVIDUAL, ((Resource) n).getURI() );
951             }
952             else {
953                 LogFactory.getLog( getClass() ).warn( "DIG language cannot yet represent enumerations of concrete literals: " + ((Literal) n).getLexicalForm() );
954                 //translateLiteral( (Literal) n, iset );
955
}
956         }
957     }
958
959
960     /** Translate a complement class to a not element */
961     protected void translateComplementClass(Element expr, OntClass cls, Model source ) {
962         // an anonymous complement of another class expression
963
Element not = addElement( expr, DIGProfile.NOT );
964         addClassDescription( not, cls.asComplementClass().getOperand(), source );
965     }
966
967
968     /** Translate an intersection class to an and element */
969     protected void translateIntersectionClass(Element expr, OntClass cls, Model source) {
970         // an anonymous intersection of class expressions
971
Element or = addElement( expr, DIGProfile.AND );
972         translateClassList( or, cls.asIntersectionClass().getOperands(), source );
973     }
974
975
976     /** Translate an union class to an or element */
977     protected void translateUnionClass(Element expr, OntClass cls, Model source) {
978         // an anonymous intersection of class expressions
979
Element or = addElement( expr, DIGProfile.OR );
980         translateClassList( or, cls.asUnionClass().getOperands(), source );
981     }
982
983
984     /**
985      * <p>Translate a cardinality restriction, with qualification</p>
986      * @param parent The parent element
987      * @param card The cardinality value
988      * @param r The restriction we are translating
989      * @param exprName The restriction type (e.g. mincardinality)
990      * @param qualType The qualification class
991      */

992     private void translateCardinalityRestriction( Element parent, int card, Restriction r, String JavaDoc exprName, Resource qualType, Model source ) {
993         Element restrict = addElement( parent, exprName );
994         restrict.setAttribute( DIGProfile.NUM, Integer.toString( card ) );
995         addNamedElement( restrict, DIGProfile.RATOM, r.getOnProperty().getURI() );
996         addClassDescription( restrict, qualType, source );
997     }
998
999
1000    /**
1001     * <p>Translate a has value restriction to DIG form. This is slightly tricky, because there is no
1002     * direct translation in the DIG concept language. We translate a has value restriction with an
1003     * individual value to a existential restriction of the singleton concept. We translate a has
1004     * value restriction with a datatype value either to an exists restriction on an integer
1005     * equality or a string equality, depending on the value.</p>
1006     * @param expr The parent expression node
1007     * @param r The has value restriction to translate
1008     */

1009    protected void translateHasValueRestriction( Element expr, HasValueRestriction r ) {
1010        RDFNode value = r.getHasValue();
1011        Property p = r.getOnProperty();
1012
1013        // we must chose whether to use the concrete domain construction or the individual domain
1014
if (value instanceof Literal) {
1015            // int or string domain?
1016
Literal lit = (Literal) value;
1017            boolean intDomain = isIntegerType( lit.getDatatype() );
1018
1019            // encode as <intequals val="x"> or <stringequals val="x">
1020
Element eq = addElement( expr, (intDomain ? DIGProfile.INTEQUALS : DIGProfile.STRINGEQUALS ) );
1021            eq.setAttribute( DIGProfile.VAL, lit.getLexicalForm() );
1022
1023            addNamedElement( eq, DIGProfile.ATTRIBUTE, p.getURI() );
1024        }
1025        else {
1026            // we model hasValue as an existential restriction on a very small set of possible values!
1027
Element some = addElement( expr, DIGProfile.SOME );
1028            addNamedElement( some, DIGProfile.RATOM, p.getURI() );
1029
1030            // we want the set of one individual
1031
Element iset = addElement( some, DIGProfile.ISET );
1032            addNamedElement( iset, DIGProfile.INDIVIDUAL, ((Resource) value).getURI() );
1033        }
1034    }
1035
1036    /**
1037     * <p>Translate a list of class descriptions into DIG concept descriptions
1038     */

1039    protected void translateClassList( Element expr, RDFList operands, Model source ) {
1040        for (Iterator i = operands.iterator(); i.hasNext(); ) {
1041            addClassDescription( expr, (Resource) i.next(), source );
1042        }
1043    }
1044
1045
1046    /** Translate the individuals in the KB to DIG form */
1047    protected void translateIndividuals( Element expr ) {
1048        for (Iterator i = m_sourceData.listIndividuals(); i.hasNext(); ) {
1049            translateIndividual( expr, (Resource) i.next() );
1050        }
1051    }
1052
1053    /** Translate the various axioms pertaining to an individual */
1054    protected void translateIndividual( Element expr, Resource r ) {
1055        Individual ind = (Individual) r.as( Individual.class );
1056        translateInstanceTypes( expr, ind );
1057
1058        for (StmtIterator i = ind.listProperties(); i.hasNext(); ) {
1059            Statement s = i.nextStatement();
1060            OntProperty p = (OntProperty) s.getPredicate().as( OntProperty.class );
1061
1062            if (p.equals( getOntLanguage().DIFFERENT_FROM())) {
1063                translateDifferentIndividuals( expr, ind, (Individual) s.getResource().as( Individual.class ) );
1064            }
1065            else if (p.equals( getOntLanguage().SAME_AS())) {
1066                translateSameIndividuals( expr, ind, (Individual) s.getResource().as( Individual.class ) );
1067            }
1068            else if (p.isObjectProperty() ||
1069                     p.isTransitiveProperty() ||
1070                     p.isSymmetricProperty() ||
1071                     p.isInverseFunctionalProperty()) {
1072                translateInstanceRole( expr, ind, p, (Individual) s.getResource().as( Individual.class ) );
1073            }
1074            else if (p.isDatatypeProperty()) {
1075                translateInstanceAttrib( expr, ind, p, s.getLiteral() );
1076            }
1077        }
1078    }
1079
1080
1081    /** The rdf:type of each individual becomes a DIG instanceof element */
1082    protected void translateInstanceTypes( Element expr, Individual ind ) {
1083        for (Iterator i = ind.listRDFTypes( true ); i.hasNext(); ) {
1084            Resource type = (Resource) i.next();
1085            Element inst = addElement( expr, DIGProfile.INSTANCEOF );
1086            addNamedElement( inst, DIGProfile.INDIVIDUAL, getResourceID( ind ) );
1087            addClassDescription( inst, (OntClass) type.as( OntClass.class ), m_sourceData );
1088        }
1089    }
1090
1091
1092    /** Translate an object property into a DIG related element */
1093    protected void translateInstanceRole( Element expr, Individual ind, OntProperty p, Individual obj) {
1094        Element related = addElement( expr, DIGProfile.RELATED );
1095        addNamedElement( related, DIGProfile.INDIVIDUAL, getResourceID( ind ) );
1096        addNamedElement( related, DIGProfile.RATOM, p.getURI() );
1097        addNamedElement( related, DIGProfile.INDIVIDUAL, getResourceID( obj ) );
1098    }
1099
1100
1101    /** Translate a datatype property into a DIG value element */
1102    protected void translateInstanceAttrib( Element expr, Individual ind, OntProperty p, Literal obj ) {
1103        Element related = addElement( expr, DIGProfile.VALUE );
1104        addNamedElement( related, DIGProfile.INDIVIDUAL, getResourceID( ind ) );
1105        addNamedElement( related, DIGProfile.ATTRIBUTE, p.getURI() );
1106
1107        translateLiteral( obj, related);
1108    }
1109
1110    /** Translate an RDF literal to an IVAL or SVAL element */
1111    protected void translateLiteral( Literal lit, Element parent ) {
1112        if (isIntegerType( lit.getDatatype() )) {
1113            Element ival = addElement( parent, DIGProfile.IVAL );
1114            ival.appendChild( parent.getOwnerDocument().createTextNode( lit.getLexicalForm() ) );
1115        }
1116        else {
1117            Element sval = addElement( parent, DIGProfile.SVAL );
1118            sval.appendChild( parent.getOwnerDocument().createTextNode( lit.getLexicalForm() ) );
1119        }
1120    }
1121
1122
1123    /** Translate differentFrom(i0, i1) we assert disjoint( iset(i0), iset(i1) ) */
1124    protected void translateDifferentIndividuals( Element expr, Individual ind, Individual other ) {
1125        Element disjoint = addElement( expr, DIGProfile.DISJOINT );
1126        Element iset0 = addElement( disjoint, DIGProfile.ISET );
1127        addNamedElement( iset0, DIGProfile.INDIVIDUAL, getResourceID( ind ) );
1128        Element iset1 = addElement( disjoint, DIGProfile.ISET );
1129        addNamedElement( iset1, DIGProfile.INDIVIDUAL, getResourceID( other ) );
1130    }
1131
1132
1133    /** Translate sameAs(i0, i1) we assert equalc( iset(i0), iset(i1) ) */
1134    protected void translateSameIndividuals( Element expr, Individual ind, Individual other ) {
1135        Element disjoint = addElement( expr, DIGProfile.EQUALC );
1136        Element iset0 = addElement( disjoint, DIGProfile.ISET );
1137        addNamedElement( iset0, DIGProfile.INDIVIDUAL, getResourceID( ind ) );
1138        Element iset1 = addElement( disjoint, DIGProfile.ISET );
1139        addNamedElement( iset1, DIGProfile.INDIVIDUAL, getResourceID( other ) );
1140    }
1141
1142
1143    /** Translate all of the roles (ObjectProperties) in the KB */
1144    protected void translateRoles( Element expr ) {
1145        Set roles = new HashSet();
1146        collectRoleProperties( roles );
1147
1148        for (Iterator i = roles.iterator(); i.hasNext(); ) {
1149            translateRole( expr, (ObjectProperty) ((Property) i.next()).as( ObjectProperty.class ), m_sourceData );
1150        }
1151    }
1152
1153    /** Translate the various axioms that can apply to roles */
1154    protected void translateRole( Element expr, ObjectProperty role, Model source ) {
1155        translateBinaryPropertyAxioms( expr, role.getURI(), DIGProfile.IMPLIESR, role.listSuperProperties(), DIGProfile.RATOM );
1156        translateBinaryPropertyAxioms( expr, role.getURI(), DIGProfile.EQUALR, role.listEquivalentProperties(), DIGProfile.RATOM );
1157        translateDomainRangeAxioms( expr, role.getURI(), DIGProfile.DOMAIN, role.listDomain(), DIGProfile.RATOM, source );
1158        translateDomainRangeAxioms( expr, role.getURI(), DIGProfile.RANGE, role.listRange(), DIGProfile.RATOM, source );
1159        translateInverseAxioms( expr, role, DIGProfile.RATOM );
1160
1161        if (role.isTransitiveProperty()) {
1162            translateUnaryPropertyAxiom( expr, role.getURI(), DIGProfile.TRANSITIVE, DIGProfile.RATOM );
1163        }
1164        if (role.isFunctionalProperty()) {
1165            translateUnaryPropertyAxiom( expr, role.getURI(), DIGProfile.FUNCTIONAL, DIGProfile.RATOM );
1166        }
1167        if (role.isInverseFunctionalProperty()) {
1168            translateInverseFunctionalAxiom( expr, role, DIGProfile.RATOM );
1169        }
1170        if (role.isSymmetricProperty()) {
1171            translateInverseAxiom( expr, role, DIGProfile.RATOM, role );
1172        }
1173    }
1174
1175    /** Translate all of the attribute (datatype properties) in the KB */
1176    protected void translateAttributes( Element expr ) {
1177        for (Iterator i = m_sourceData.listDatatypeProperties(); i.hasNext(); ) {
1178            translateAttribute( expr, (DatatypeProperty) ((Property) i.next()).as( DatatypeProperty.class ), m_sourceData );
1179        }
1180    }
1181
1182    /** Attributes (datatype properties) have fewer axiom choices than roles */
1183    protected void translateAttribute( Element expr, DatatypeProperty attrib, Model source ) {
1184        translateBinaryPropertyAxioms( expr, attrib.getURI(), DIGProfile.IMPLIESR, attrib.listSuperProperties(), DIGProfile.ATTRIBUTE);
1185        translateBinaryPropertyAxioms( expr, attrib.getURI(), DIGProfile.EQUALR, attrib.listEquivalentProperties(), DIGProfile.ATTRIBUTE );
1186        translateDomainRangeAxioms( expr, attrib.getURI(), DIGProfile.DOMAIN, attrib.listDomain(), DIGProfile.ATTRIBUTE, source );
1187        translateAttribRangeAxioms( expr, attrib.getURI(), attrib.listRange(), DIGProfile.ATTRIBUTE );
1188
1189        if (attrib.isFunctionalProperty()) {
1190            translateUnaryPropertyAxiom( expr, attrib.getURI(), DIGProfile.FUNCTIONAL, DIGProfile.ATTRIBUTE );
1191        }
1192    }
1193
1194    /** Helper method for binary axioms each argument of which is an ratom element */
1195    protected void translateBinaryPropertyAxioms( Element expr, String JavaDoc propURI, String JavaDoc axiomType, Iterator i, String JavaDoc propType ) {
1196        while (i.hasNext()) {
1197            Property prop = (Property) i.next();
1198            Element binaryAxiom = addElement( expr, axiomType );
1199            addNamedElement( binaryAxiom, propType, propURI );
1200            addNamedElement( binaryAxiom, propType, prop.getURI() );
1201        }
1202    }
1203
1204    /** Helper method for unary axioms, the argument of which is an ratom element */
1205    protected void translateUnaryPropertyAxiom( Element expr, String JavaDoc propURI, String JavaDoc axiomType, String JavaDoc propType ) {
1206        Element unaryAxiom = addElement( expr, axiomType );
1207        addNamedElement( unaryAxiom, propType, propURI );
1208    }
1209
1210    /** Domain and range are translated as dig domain and range elements */
1211    protected void translateDomainRangeAxioms( Element expr, String JavaDoc propURI, String JavaDoc axiomType, Iterator i, String JavaDoc propType, Model source ) {
1212        while (i.hasNext()) {
1213            Element drAxiom = addElement( expr, axiomType );
1214            addNamedElement( drAxiom, propType, propURI );
1215            addClassDescription( drAxiom, (Resource) i.next(), source );
1216        }
1217    }
1218
1219    /** Concrete ranges have special treatment*/
1220    protected void translateAttribRangeAxioms( Element expr, String JavaDoc propURI, Iterator i, String JavaDoc propType ) {
1221        while (i.hasNext()) {
1222            Resource type = (Resource) i.next();
1223            RDFDatatype dt = TypeMapper.getInstance().getTypeByName( type.getURI() );
1224
1225            Element drAxiom = addElement( expr, isIntegerType( dt ) ? DIGProfile.RANGEINT : DIGProfile.RANGESTRING );
1226            addNamedElement( drAxiom, propType, propURI );
1227        }
1228    }
1229
1230    /** Axioms for all of the inverses of a property */
1231    protected void translateInverseAxioms( Element expr, ObjectProperty p, String JavaDoc propType ) {
1232        for (Iterator i = p.listInverse(); i.hasNext(); ) {
1233            translateInverseAxiom(expr, p, propType, (Property) i.next() );
1234        }
1235    }
1236
1237    /** Translate inverseOf as equality between the role and the inverse of the named inverse role */
1238    protected void translateInverseAxiom( Element expr, Property p, String JavaDoc propType, Property inv ) {
1239        Element equalr = addElement( expr, DIGProfile.EQUALR );
1240        addNamedElement( equalr, propType, p.getURI() );
1241        Element inverse = addElement( equalr, DIGProfile.INVERSE );
1242        addNamedElement( inverse, propType, inv.getURI() );
1243    }
1244
1245
1246    /** To translate an inverse functional property, we must introduce a new skolem constant for the inverse role */
1247    protected void translateInverseFunctionalAxiom( Element expr, ObjectProperty role, String JavaDoc propType ) {
1248        // we need a skolem name for the inverse property
1249
String JavaDoc skolemName = getSkolemName( role.getLocalName() );
1250
1251        // first we make the skolem role functional
1252
addNamedElement( expr, DIGProfile.DEFROLE, skolemName );
1253        Element functional = addElement( expr, DIGProfile.FUNCTIONAL );
1254        addNamedElement( functional, propType, skolemName );
1255
1256        // then we make its inverse equal to role
1257
Element equalr = addElement( expr, DIGProfile.EQUALR );
1258        addNamedElement( equalr, propType, role.getURI() );
1259        Element inverse = addElement( equalr, DIGProfile.INVERSE );
1260        addNamedElement( inverse, propType, skolemName );
1261    }
1262
1263
1264    /** Translate all of the AllDifferent axioms in the KB */
1265    protected void translateAllDifferentAxioms( Element expr ) {
1266        if (m_sourceData.getProfile().ALL_DIFFERENT() != null) {
1267            for (Iterator i = m_sourceData.listAllDifferent(); i.hasNext(); ) {
1268                AllDifferent ad = (AllDifferent) ((Resource) i.next()).as( AllDifferent.class );
1269                translateAllDifferent( expr, ad.getDistinctMembers() );
1270            }
1271        }
1272    }
1273
1274
1275    /** Translate a single AllDifferent declaration as a set of pair-wise disjoints */
1276    protected void translateAllDifferent( Element expr, RDFList diffMembers ) {
1277        List dm = diffMembers.asJavaList();
1278
1279        for (int i = 0; i < dm.size(); i++) {
1280            Individual ind0 = (Individual) ((Resource) dm.get(i)).as( Individual.class );
1281
1282            for (int j = i+1; j < dm.size(); j++) {
1283                Individual ind1 = (Individual) ((Resource) dm.get(j)).as( Individual.class );
1284                translateDifferentIndividuals( expr, ind0, ind1 );
1285            }
1286        }
1287    }
1288
1289
1290    /**
1291     * <p>Answer true if the given RDF datatype represents an integer value</p>
1292     */

1293    private boolean isIntegerType( RDFDatatype type ) {
1294        String JavaDoc typeURI = (type != null) ? type.getURI() : null;
1295        return typeURI != null && XSD_INT_TYPES.contains( typeURI );
1296    }
1297
1298
1299    /** Answer a skolem constant, using the given name as a root */
1300    private String JavaDoc getSkolemName( String JavaDoc root ) {
1301        return "skolem(" + root + "," + m_skolemCounter++ + ")";
1302
1303    }
1304
1305
1306
1307    /**
1308     * <p>Answer an iterator of the individual names known to the DIG reasoner, from the cache if possible.</p>
1309     * @return An iterator of the known individual names
1310     */

1311    protected Set getKnownIndividuals() {
1312        if (!m_indNamesAsked) {
1313            m_indNames.addAll( collectNamedTerms( DIGProfile.ALL_INDIVIDUALS,
1314                                                  new String JavaDoc[] {DIGProfile.INDIVIDUAL_SET, DIGProfile.INDIVIDUAL} ) );
1315            m_indNamesAsked = true;
1316        }
1317
1318        return m_indNames;
1319    }
1320
1321
1322    /**
1323     * <p>Answer an iterator of the concept names known to the DIG reasoner, from the cache if possible.</p>
1324     * @return An iterator of the known concept names
1325     */

1326    protected Set getKnownConcepts() {
1327        if (!m_conceptNamesAsked) {
1328            m_conceptNames.addAll( collectNamedTerms( DIGProfile.ALL_CONCEPT_NAMES,
1329                                                new String JavaDoc[] {DIGProfile.CONCEPT_SET, DIGProfile.SYNONYMS, DIGProfile.CATOM} ) );
1330            m_conceptNamesAsked = true;
1331        }
1332
1333        return m_conceptNames;
1334    }
1335
1336
1337    /**
1338     * <p>Answer an iterator of the role names known to the DIG reasoner, from the cache if possible.</p>
1339     * @return An iterator of the known role names
1340     */

1341    protected Set getKnownRoles() {
1342        if (!m_roleNamesAsked) {
1343            m_roleNames.addAll( collectNamedTerms( DIGProfile.ALL_ROLE_NAMES,
1344                                             new String JavaDoc[] {DIGProfile.ROLE_SET, DIGProfile.SYNONYMS, DIGProfile.RATOM} ) );
1345            m_roleNamesAsked = true;
1346        }
1347
1348        return m_roleNames;
1349    }
1350
1351
1352    /**
1353     * <p>Answer an iterator of named terms known to the DIG reasoner, from the cache if possible.</p>
1354     * @param queryType The query verb for the ask
1355     * @param path A list of element names to extract the term names from the returned document
1356     * @return An iterator of the known names of a particular type
1357     */

1358    protected Set collectNamedTerms( String JavaDoc queryType, String JavaDoc[] path ) {
1359        Set names = new HashSet();
1360
1361        // query the DIG ks for the currently known individuals
1362
Document query = getConnection().createDigVerb( DIGProfile.ASKS, getProfile() );
1363        createQueryElement( query, queryType );
1364        Document response = getConnection().sendDigVerb( query, getProfile() );
1365
1366        // build the path to extract the names
1367
SimpleXMLPath p = new SimpleXMLPath( true );
1368        for (int j = 0; j < path.length; j++) {
1369            p.appendElementPath( path[j] );
1370        }
1371        p.appendAttrPath( DIGProfile.NAME );
1372
1373        // collect them into a cached set
1374
addAll( p.getAll( response ), names );
1375
1376        return names;
1377    }
1378
1379
1380    /** Check whether the given node represents a class in the premises */
1381    private boolean isPremisesClass( com.hp.hpl.jena.graph.Node node, Model premises ) {
1382        RDFNode rdfNode = premises.getRDFNode( node );
1383        Profile oProf = getOntLanguage();
1384
1385        if (rdfNode instanceof Resource) {
1386            Resource r = (Resource) rdfNode;
1387            Resource any = null;
1388
1389            return
1390                ((oProf.CLASS() != null) && premises.contains( r, RDF.type, oProf.CLASS()) ) ||
1391                ((oProf.RESTRICTION() != null) && premises.contains( r, RDF.type, oProf.RESTRICTION()) ) ||
1392                ((oProf.SUB_CLASS_OF() != null) && premises.contains( r, oProf.SUB_CLASS_OF(), any ) ) ||
1393                ((oProf.SUB_CLASS_OF() != null) && premises.contains( any, oProf.SUB_CLASS_OF(), r ) ) ||
1394                ((oProf.UNION_OF() != null) && premises.contains( r, oProf.SUB_CLASS_OF(), any ) ) ||
1395                ((oProf.INTERSECTION_OF() != null) && premises.contains( r, oProf.SUB_CLASS_OF(), any ) ) ||
1396                ((oProf.COMPLEMENT_OF() != null) && premises.contains( r, oProf.SUB_CLASS_OF(), any ) ) ||
1397                ((oProf.DISJOINT_WITH() != null) && premises.contains( r, oProf.DISJOINT_WITH(), any ) ) ||
1398                ((oProf.EQUIVALENT_CLASS() != null) && premises.contains( r, oProf.EQUIVALENT_CLASS(), any ));
1399        }
1400
1401        // by default it is not a class
1402
return false;
1403    }
1404
1405    /** Check whether the given node represents a class in the premises */
1406    private boolean isPremisesRole( com.hp.hpl.jena.graph.Node node, Model premises ) {
1407        RDFNode rdfNode = premises.getRDFNode( node );
1408        Profile oProf = getOntLanguage();
1409
1410        if (rdfNode instanceof Resource) {
1411            Resource r = (Resource) rdfNode;
1412            Resource any = null;
1413
1414            return
1415                ((oProf.PROPERTY() != null) && premises.contains( r, RDF.type, oProf.PROPERTY()) ) ||
1416                ((oProf.OBJECT_PROPERTY() != null) && premises.contains( r, RDF.type, oProf.OBJECT_PROPERTY()) ) ||
1417                ((oProf.DATATYPE_PROPERTY() != null) && premises.contains( r, RDF.type, oProf.DATATYPE_PROPERTY()) ) ||
1418                ((oProf.TRANSITIVE_PROPERTY() != null) && premises.contains( r, RDF.type, oProf.TRANSITIVE_PROPERTY()) ) ||
1419                ((oProf.FUNCTIONAL_PROPERTY() != null) && premises.contains( r, RDF.type, oProf.FUNCTIONAL_PROPERTY()) ) ||
1420                ((oProf.INVERSE_FUNCTIONAL_PROPERTY() != null) && premises.contains( r, RDF.type, oProf.INVERSE_FUNCTIONAL_PROPERTY())) ||
1421                ((oProf.SYMMETRIC_PROPERTY() != null) && premises.contains( r, RDF.type, oProf.SYMMETRIC_PROPERTY()) ) ||
1422                ((oProf.SUB_PROPERTY_OF() != null) && premises.contains( r, oProf.SUB_PROPERTY_OF(), any ) ) ||
1423                ((oProf.SUB_PROPERTY_OF() != null) && premises.contains( any, oProf.SUB_PROPERTY_OF(), r ) ) ||
1424                ((oProf.INVERSE_OF() != null) && premises.contains( r, oProf.INVERSE_OF (), any ) ) ||
1425                ((oProf.INVERSE_OF() != null) && premises.contains( any, oProf.INVERSE_OF (), r ) );
1426        }
1427
1428        // by default it is not a class
1429
return false;
1430    }
1431
1432    /** Normalise any variables to Node.ANY */
1433    private com.hp.hpl.jena.graph.Node normaliseNode( com.hp.hpl.jena.graph.Node n ) {
1434        return n.isConcrete() ? n : com.hp.hpl.jena.graph.Node.ANY;
1435    }
1436
1437
1438    //==============================================================================
1439
// Inner class definitions
1440
//==============================================================================
1441

1442
1443
1444    /** Encapsulates the identification information from a DIG reasoner */
1445    private class DigIdentifierImpl
1446        implements DIGIdentifier
1447    {
1448        private Document m_id;
1449
1450        private DigIdentifierImpl( Document id ) {
1451            m_id = id;
1452        }
1453
1454        public String JavaDoc getName() {return m_id.getDocumentElement().getAttribute( DIGProfile.NAME ); }
1455        public String JavaDoc getVersion() {return m_id.getDocumentElement().getAttribute( DIGProfile.VERSION ); }
1456        public String JavaDoc getMessage() {return m_id.getDocumentElement().getAttribute( DIGProfile.MESSAGE ); }
1457
1458        public Iterator supportsLanguage() {return supports( DIGProfile.LANGUAGE ); }
1459        public Iterator supportsTell() {return supports( DIGProfile.TELL ); }
1460        public Iterator supportsAsk() {return supports( DIGProfile.ASK ); }
1461
1462        private Iterator supports( String JavaDoc support ) {
1463            Element supports = getChild( m_id.getDocumentElement(), DIGProfile.SUPPORTS );
1464            return childElementNames( getChild( supports, support ) );
1465        }
1466
1467        /** Answer an iterator of the child node names for a given node */
1468        private Iterator childElementNames( Element node ) {
1469            ArrayList l = new ArrayList();
1470            NodeList nl = node.getChildNodes();
1471
1472            for (int i = 0; i < nl.getLength(); i++) {
1473                org.w3c.dom.Node JavaDoc n = nl.item(i);
1474
1475                // ignore whitespace text etc
1476
if (n instanceof Element) {
1477                    l.add( n.getNodeName() );
1478                }
1479            }
1480
1481            return l.iterator();
1482        }
1483
1484        /** Answer the first named child node */
1485        private Element getChild( Element node, String JavaDoc name ) {
1486            return (Element) node.getElementsByTagName( name ).item( 0 );
1487        }
1488    }
1489}
1490
1491
1492/*
1493 * (c) Copyright 2001, 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
1494 * All rights reserved.
1495 *
1496 * Redistribution and use in source and binary forms, with or without
1497 * modification, are permitted provided that the following conditions
1498 * are met:
1499 * 1. Redistributions of source code must retain the above copyright
1500 * notice, this list of conditions and the following disclaimer.
1501 * 2. Redistributions in binary form must reproduce the above copyright
1502 * notice, this list of conditions and the following disclaimer in the
1503 * documentation and/or other materials provided with the distribution.
1504 * 3. The name of the author may not be used to endorse or promote products
1505 * derived from this software without specific prior written permission.
1506 *
1507 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1508 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1509 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1510 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1511 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1512 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1513 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1514 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1515 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1516 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1517 */

1518
Popular Tags