KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > hp > hpl > jena > ontology > impl > OntClassImpl


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 27-Mar-2003
9  * Filename $RCSfile: OntClassImpl.java,v $
10  * Revision $Revision: 1.48 $
11  * Release status $State: Exp $
12  *
13  * Last modified on $Date: 2005/04/11 16:41:41 $
14  * by $Author: ian_dickinson $
15  *
16  * (c) Copyright 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
17  * (see footer for full conditions)
18  *****************************************************************************/

19
20 // Package
21
///////////////
22
package com.hp.hpl.jena.ontology.impl;
23
24
25
26 // Imports
27
///////////////
28
import com.hp.hpl.jena.ontology.*;
29 import com.hp.hpl.jena.enhanced.*;
30 import com.hp.hpl.jena.graph.*;
31 import com.hp.hpl.jena.graph.query.*;
32 import com.hp.hpl.jena.rdf.model.*;
33 import com.hp.hpl.jena.reasoner.*;
34 import com.hp.hpl.jena.util.iterator.*;
35 import com.hp.hpl.jena.vocabulary.*;
36
37 import java.util.*;
38
39
40 /**
41  * <p>
42  * Implementation of the ontology abstraction representing ontology classes.
43  * </p>
44  *
45  * @author Ian Dickinson, HP Labs
46  * (<a HREF="mailto:Ian.Dickinson@hp.com" >email</a>)
47  * @version CVS $Id: OntClassImpl.java,v 1.48 2005/04/11 16:41:41 ian_dickinson Exp $
48  */

49 public class OntClassImpl
50     extends OntResourceImpl
51     implements OntClass
52 {
53     // Constants
54
//////////////////////////////////
55

56     /* LDP never returns properties in these namespaces */
57     private static final String JavaDoc[] IGNORE_NAMESPACES = new String JavaDoc[] {
58             OWL.NS,
59             DAMLVocabulary.NAMESPACE_DAML_2001_03_URI,
60             RDF.getURI(),
61             RDFS.getURI(),
62             ReasonerVocabulary.RBNamespace
63     };
64
65
66     // Static variables
67
//////////////////////////////////
68

69     /**
70      * A factory for generating OntClass facets from nodes in enhanced graphs.
71      * Note: should not be invoked directly by user code: use
72      * {@link com.hp.hpl.jena.rdf.model.RDFNode#as as()} instead.
73      */

74     public static Implementation factory = new Implementation() {
75         public EnhNode wrap( Node n, EnhGraph eg ) {
76             if (canWrap( n, eg )) {
77                 return new OntClassImpl( n, eg );
78             }
79             else {
80                 throw new ConversionException( "Cannot convert node " + n.toString() + " to OntClass: it does not have rdf:type owl:Class or equivalent");
81             }
82         }
83
84         public boolean canWrap( Node node, EnhGraph eg ) {
85             // node will support being an OntClass facet if it has rdf:type owl:Class or equivalent
86
Profile profile = (eg instanceof OntModel) ? ((OntModel) eg).getProfile() : null;
87             return (profile != null) && profile.isSupported( node, eg, OntClass.class );
88         }
89     };
90
91
92     // Instance variables
93
//////////////////////////////////
94

95     /** Query for properties with this class as domain */
96     protected BindingQueryPlan m_domainQuery;
97
98     /** Query for properties restricted by this class */
99     protected BindingQueryPlan m_restrictionPropQuery = null;
100
101
102     // Constructors
103
//////////////////////////////////
104

105     /**
106      * <p>
107      * Construct an ontology class node represented by the given node in the given graph.
108      * </p>
109      *
110      * @param n The node that represents the resource
111      * @param g The enh graph that contains n
112      */

113     public OntClassImpl( Node n, EnhGraph g ) {
114         super( n, g );
115
116         // pre-built queries
117
// ?x a rdf:Property ; rdfs:domain this.
118
Query q = new Query();
119         q.addMatch( Query.X, getProfile().DOMAIN().asNode(), asNode() );
120
121         m_domainQuery = getModel().queryHandler().prepareBindings( q, new Node[] {Query.X} );
122
123         // this rdfs:subClassOf ?x. ?x owl:onProperty ?y.
124
if (getProfile().ON_PROPERTY() != null) {
125             q = new Query();
126             q.addMatch( asNode(), getProfile().SUB_CLASS_OF().asNode(), Query.X );
127             q.addMatch( Query.X, getProfile().ON_PROPERTY().asNode(), Query.Y );
128
129             m_restrictionPropQuery = getModel().queryHandler().prepareBindings( q, new Node[] {Query.Y} );
130         }
131     }
132
133
134     // External signature methods
135
//////////////////////////////////
136

137     // subClassOf
138

139     /**
140      * <p>Assert that this class is sub-class of the given class. Any existing
141      * statements for <code>subClassOf</code> will be removed.</p>
142      * @param cls The class that this class is a sub-class of
143      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
144      */

145     public void setSuperClass( Resource cls ) {
146         setPropertyValue( getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF", cls );
147     }
148
149     /**
150      * <p>Add a super-class of this class.</p>
151      * @param cls A class that is a super-class of this class.
152      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
153      */

154     public void addSuperClass( Resource cls ) {
155         addPropertyValue( getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF", cls );
156     }
157
158     /**
159      * <p>Answer a class that is the super-class of this class. If there is
160      * more than one such class, an arbitrary selection is made.</p>
161      * @return A super-class of this class
162      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
163      */

164     public OntClass getSuperClass() {
165         return (OntClass) objectAs( getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF", OntClass.class );
166     }
167
168     /**
169      * <p>Answer an iterator over all of the classes that are declared to be super-classes of
170      * this class. Each element of the iterator will be an {@link OntClass}.</p>
171      * @return An iterator over the super-classes of this class.
172      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
173      */

174     public ExtendedIterator listSuperClasses() {
175         return listSuperClasses( false );
176     }
177
178     /**
179      * <p>Answer an iterator over all of the classes that are declared to be super-classes of
180      * this class. Each element of the iterator will be an {@link OntClass}.
181      * See {@link #listSubClasses( boolean )} for a full explanation of the <em>direct</em>
182      * parameter.
183      * </p>
184      *
185      * @param direct If true, only answer the direcly adjacent classes in the
186      * super-class relation: i&#046;e&#046; eliminate any class for which there is a longer route
187      * to reach that child under the super-class relation.
188      * @return an iterator over the resources representing this class's sub-classes.
189      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
190      */

191     public ExtendedIterator listSuperClasses( boolean direct ) {
192         return UniqueExtendedIterator.create(
193                 listDirectPropertyValues( getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF", OntClass.class, getProfile().SUB_CLASS_OF(), direct, false )
194                 .filterDrop( new SingleEqualityFilter( this ) ) );
195     }
196
197     /**
198      * <p>Answer true if the given class is a super-class of this class.</p>
199      * @param cls A class to test.
200      * @return True if the given class is a super-class of this class.
201      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
202      */

203     public boolean hasSuperClass( Resource cls ) {
204         return hasSuperClass( cls, false );
205     }
206
207     /**
208      * <p>Answer true if this class has any super-class in the model. Note that
209      * when using a reasoner, all OWL classes have owl:Thing as a super-class.</p>
210      * @return True if this class has any known super-class.
211      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
212      */

213     public boolean hasSuperClass() {
214         return getSuperClass() != null;
215     }
216
217     /**
218      * <p>Answer true if the given class is a super-class of this class.
219      * See {@link #listSubClasses( boolean )} for a full explanation of the <em>direct</em>
220      * parameter.
221      * </p>
222      * @param cls A class to test.
223      * @param direct If true, only search the classes that are directly adjacent to this
224      * class in the class hierarchy.
225      * @return True if the given class is a super-class of this class.
226      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
227      */

228     public boolean hasSuperClass( Resource cls, boolean direct ) {
229         if (!direct) {
230             // don't need any special case, we just get the property
231
return hasPropertyValue( getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF", cls );
232         }
233         else {
234             // we want the direct, not general relationship
235
// first try to find an inf graph that can do the work for us
236
InfGraph ig = null;
237             if (getGraph() instanceof InfGraph) {
238                 ig = (InfGraph) getGraph();
239             }
240             else if (getGraph() instanceof OntModel) {
241                 OntModel m = (OntModel) getGraph();
242                 if (m.getGraph() instanceof InfGraph) {
243                     ig = (InfGraph) m.getGraph();
244                 }
245             }
246
247             if (ig != null && ig.getReasoner().supportsProperty( ReasonerVocabulary.directSubClassOf )) {
248                 // we can look this up directly
249
return hasPropertyValue( ReasonerVocabulary.directSubClassOf, "direct sub-class", cls );
250             }
251             else {
252                 // otherwise, not an inf-graph or the given inf-graph does not support direct directly (:-)
253
return hasSuperClassDirect(cls);
254             }
255         }
256     }
257
258     /**
259      * <p>Remove the given class from the super-classes of this class. If this statement
260      * is not true of the current model, nothing happens.</p>
261      * @param cls A class to be removed from the super-classes of this class
262      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} class is not supported in the current language profile.
263      */

264     public void removeSuperClass( Resource cls ) {
265         removePropertyValue( getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF", cls );
266     }
267
268     /**
269      * <p>Assert that this class is super-class of the given class. Any existing
270      * statements for <code>subClassOf</code> on <code>prop</code> will be removed.</p>
271      * @param cls The class that is a sub-class of this class
272      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
273      */

274     public void setSubClass( Resource cls ) {
275         // first we have to remove all of the inverse sub-class links
276
checkProfile( getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF" );
277         for (StmtIterator i = getModel().listStatements( null, getProfile().SUB_CLASS_OF(), this ); i.hasNext(); ) {
278             i.removeNext();
279         }
280
281         ((OntClass) cls.as( OntClass.class )).addSuperClass( this );
282     }
283
284     /**
285      * <p>Add a sub-class of this class.</p>
286      * @param cls A class that is a sub-class of this class.
287      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
288      */

289     public void addSubClass( Resource cls ) {
290         ((OntClass) cls.as( OntClass.class )).addSuperClass( this );
291     }
292
293     /**
294      * <p>Answer a class that is the sub-class of this class. If there is
295      * more than one such class, an arbitrary selection is made. If
296      * there is no such class, return null.</p>
297      * @return A sub-class of this class or null
298      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()}
299      * property is not supported in the current language profile.
300      */

301     public OntClass getSubClass() {
302         checkProfile( getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF" );
303         StmtIterator i = getModel().listStatements( null, getProfile().SUB_CLASS_OF(), this );
304         try {
305             if (i.hasNext()) {
306                 return (OntClass) i.nextStatement()
307                                    .getSubject()
308                                    .as( OntClass.class );
309             }
310             else {
311                 return null;
312             }
313         }
314         finally {
315             i.close();
316         }
317     }
318
319     /**
320      * <p>Answer an iterator over all of the classes that are declared to be sub-classes of
321      * this class. Each element of the iterator will be an {@link OntClass}.</p>
322      * @return An iterator over the sub-classes of this class.
323      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
324      */

325     public ExtendedIterator listSubClasses() {
326         return listSubClasses( false );
327     }
328
329     /**
330      * <p>
331      * Answer an iterator over the classes that are declared to be sub-classes of
332      * this class. Each element of the iterator will be an {@link OntClass}. The
333      * distinguishing extra parameter for this method is the flag <code>direct</code>
334      * that allows some selectivity over the classes that appear in the iterator.
335      * Consider the following scenario:
336      * <code><pre>
337      * :B rdfs:subClassOf :A.
338      * :C rdfs:subClassOf :A.
339      * :D rdfs:subClassof :C.
340      * </pre></code>
341      * (so A has two sub-classes, B and C, and C has sub-class D). In a raw model, with
342      * no inference support, listing the sub-classes of A will answer B and C. In an
343      * inferencing model, <code>rdfs:subClassOf</code> is known to be transitive, so
344      * the sub-classes iterator will include D. The <code>direct</code> sub-classes
345      * are those members of the closure of the subClassOf relation, restricted to classes that
346      * cannot be reached by a longer route, i.e. the ones that are <em>directly</em> adjacent
347      * to the given root. Thus, the direct sub-classes of A are B and C only, and not D -
348      * even in an inferencing graph. Note that this is not the same as the entailments
349      * from the raw graph. Suppose we add to this example:
350      * <code><pre>
351      * :D rdfs:subClassof :A.
352      * </pre></code>
353      * Now, in the raw graph, A has sub-class C. But the direct sub-classes of A remain
354      * B and C, since there is a longer path A-C-D that means that D is not a direct sub-class
355      * of A. The assertion in the raw graph that A has sub-class D is essentially redundant,
356      * since this can be inferred from the closure of the graph.
357      * </p>
358      * <p>
359      * <strong>Note:</strong> This is is a change from the behaviour of Jena 1, which took a
360      * parameter <code>closed</code> to compute the closure over transitivity and equivalence
361      * of sub-classes. The closure capability in Jena2 is determined by the inference engine
362      * that is wrapped with the ontology model. The direct parameter is provided to allow,
363      * for exmaple, a level-by-level traversal of the class hierarchy, starting at some given
364      * root.
365      * </p>
366      *
367      * @param direct If true, only answer the direcly adjacent classes in the
368      * sub-class relation: i&#046;e&#046; eliminate any class for which there is a longer route
369      * to reach that child under the sub-class relation.
370      * @return an iterator over the resources representing this class's sub-classes
371      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
372      */

373     public ExtendedIterator listSubClasses( boolean direct ) {
374         return UniqueExtendedIterator.create(
375                 listDirectPropertyValues( getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF", OntClass.class, getProfile().SUB_CLASS_OF(), direct, true )
376                 .filterDrop( new SingleEqualityFilter( this ) ) );
377     }
378
379
380     /**
381      * <p>Answer true if the given class is a sub-class of this class.</p>
382      * @param cls A class to test.
383      * @return True if the given class is a sub-class of this class.
384      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
385      */

386     public boolean hasSubClass( Resource cls ) {
387         return hasSubClass( cls, false );
388     }
389
390     /**
391      * <p>Answer true if this class has any sub-class in the model. Note that
392      * when using a reasoner, all OWL classes have owl:Nothing as a sub-class.</p>
393      * @return True if this class has any known sub-class.
394      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
395      */

396     public boolean hasSubClass() {
397         return getSubClass() != null;
398     }
399
400     /**
401      * <p>Answer true if the given class is a sub-class of this class.
402      * See {@link #listSubClasses( boolean )} for a full explanation of the <em>direct</em>
403      * parameter.
404      * </p>
405      * @param cls A class to test.
406      * @param direct If true, only search the classes that are directly adjacent to this
407      * class in the class hierarchy.
408      * @return True if the given class is a sub-class of this class.
409      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
410      */

411     public boolean hasSubClass( Resource cls, boolean direct ) {
412         if (getModel() instanceof OntModel &&
413             (cls.getModel() == null || !(cls.getModel() instanceof OntModel)))
414         {
415             // could be outside an ontmodel if a constant
416
cls = (Resource) cls.inModel( getModel() );
417         }
418         return ((OntClass) cls.as( OntClass.class )).hasSuperClass( this, direct );
419     }
420
421     /**
422      * <p>Remove the given class from the sub-classes of this class. If this statement
423      * is not true of the current model, nothing happens.</p>
424      * @param cls A class to be removed from the sub-classes of this class
425      * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} class is not supported in the current language profile.
426      */

427     public void removeSubClass( Resource cls ) {
428         ((OntClass) cls.as( OntClass.class)).removeSuperClass( this );
429     }
430
431
432     // equivalentClass
433

434     /**
435      * <p>Assert that the given class is equivalent to this class. Any existing
436      * statements for <code>equivalentClass</code> will be removed.</p>
437      * @param cls The class that this class is a equivalent to.
438      * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()} property is not supported in the current language profile.
439      */

440     public void setEquivalentClass( Resource cls ) {
441         setPropertyValue( getProfile().EQUIVALENT_CLASS(), "EQUIVALENT_CLASS", cls );
442     }
443
444     /**
445      * <p>Add a class that is equivalent to this class.</p>
446      * @param cls A class that is equivalent to this class.
447      * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()} property is not supported in the current language profile.
448      */

449     public void addEquivalentClass( Resource cls ) {
450         addPropertyValue( getProfile().EQUIVALENT_CLASS(), "EQUIVALENT_CLASS", cls );
451     }
452
453     /**
454      * <p>Answer a class that is equivalent to this class. If there is
455      * more than one such class, an arbitrary selection is made.</p>
456      * @return A class equivalent to this class
457      * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()} property is not supported in the current language profile.
458      */

459     public OntClass getEquivalentClass() {
460         return (OntClass) objectAs( getProfile().EQUIVALENT_CLASS(), "EQUIVALENT_CLASS", OntClass.class );
461     }
462
463     /**
464      * <p>Answer an iterator over all of the classes that are declared to be equivalent classes to
465      * this class. Each element of the iterator will be an {@link OntClass}.</p>
466      * @return An iterator over the classes equivalent to this class.
467      * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()} property is not supported in the current language profile.
468      */

469     public ExtendedIterator listEquivalentClasses() {
470         return UniqueExtendedIterator.create( listAs( getProfile().EQUIVALENT_CLASS(), "EQUIVALENT_CLASS", OntClass.class ) );
471     }
472
473     /**
474      * <p>Answer true if the given class is equivalent to this class.</p>
475      * @param cls A class to test for
476      * @return True if the given property is equivalent to this class.
477      * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()} property is not supported in the current language profile.
478      */

479     public boolean hasEquivalentClass( Resource cls ) {
480         return hasPropertyValue( getProfile().EQUIVALENT_CLASS(), "EQUIVALENT_CLASS", cls );
481     }
482
483     /**
484      * <p>Remove the statement that this class and the given class are
485      * equivalent. If this statement
486      * is not true of the current model, nothing happens.</p>
487      * @param cls A class that may be declared to be equivalent to this class, and which is no longer equivalent
488      * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()()} property is not supported in the current language profile.
489      */

490     public void removeEquivalentClass( Resource cls ) {
491         removePropertyValue( getProfile().EQUIVALENT_CLASS(), "EQUIVALENT_CLASS", cls );
492     }
493
494     // disjointWith
495

496     /**
497      * <p>Assert that this class is disjoint with the given class. Any existing
498      * statements for <code>disjointWith</code> will be removed.</p>
499      * @param cls The property that this class is disjoint with.
500      * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()} property is not supported in the current language profile.
501      */

502     public void setDisjointWith( Resource cls ) {
503         setPropertyValue( getProfile().DISJOINT_WITH(), "DISJOINT_WITH", cls );
504     }
505
506     /**
507      * <p>Add a class that this class is disjoint with.</p>
508      * @param cls A class that has no instances in common with this class.
509      * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()} property is not supported in the current language profile.
510      */

511     public void addDisjointWith( Resource cls ) {
512         addPropertyValue( getProfile().DISJOINT_WITH(), "DISJOINT_WITH", cls );
513     }
514
515     /**
516      * <p>Answer a class with which this class is disjoint. If there is
517      * more than one such class, an arbitrary selection is made.</p>
518      * @return A class disjoint with this class
519      * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()} property is not supported in the current language profile.
520      */

521     public OntClass getDisjointWith() {
522         return (OntClass) objectAs( getProfile().DISJOINT_WITH(), "DISJOINT_WITH", OntClass.class );
523     }
524
525     /**
526      * <p>Answer an iterator over all of the classes that this class is declared to be disjoint with.
527      * Each element of the iterator will be an {@link OntClass}.</p>
528      * @return An iterator over the classes disjoint with this class.
529      * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()} property is not supported in the current language profile.
530      */

531     public ExtendedIterator listDisjointWith() {
532         return UniqueExtendedIterator.create( listAs( getProfile().DISJOINT_WITH(), "DISJOINT_WITH", OntClass.class ) );
533     }
534
535     /**
536      * <p>Answer true if this class is disjoint with the given class.</p>
537      * @param cls A class to test
538      * @return True if the this class is disjoint with the the given class.
539      * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()} property is not supported in the current language profile.
540      */

541     public boolean isDisjointWith( Resource cls ) {
542         return hasPropertyValue( getProfile().DISJOINT_WITH(), "DISJOINT_WITH", cls );
543     }
544
545     /**
546      * <p>Remove the statement that this class and the given class are
547      * disjoint. If this statement
548      * is not true of the current model, nothing happens.</p>
549      * @param cls A class that may be declared to be disjoint with this class, and which is no longer disjoint
550      * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()()()} property is not supported in the current language profile.
551      */

552     public void removeDisjointWith( Resource cls ) {
553         removePropertyValue( getProfile().DISJOINT_WITH(), "DISJOINT_WITH", cls );
554     }
555
556
557     // other utility methods
558

559     /**
560      * <p>Answer an iteration of the properties associated with a frame-like
561      * view of this class. Note that many cases of determining whether a
562      * property is associated with a class depends on RDFS or OWL reasoning.
563      * This method may therefore return complete results only in models that
564      * have an attached reasoner.
565      * See the
566      * <a HREF="../../../../../../how-to/rdf-frames.html">RDF frames how-to</a>
567      * for full details.<p>
568      * @return An iteration of the properties that are associated with this class
569      * by their domain.
570      */

571     public ExtendedIterator listDeclaredProperties() {
572         return listDeclaredProperties( false );
573     }
574
575
576     /**
577      * <p>Answer an iteration of the properties associated with a frame-like
578      * view of this class. Note that many cases of determining whether a
579      * property is associated with a class depends on RDFS or OWL reasoning.
580      * This method may therefore return complete results only in models that
581      * have an attached reasoner. See the
582      * <a HREF="../../../../../../how-to/rdf-frames.html">RDF frames how-to</a>
583      * for full details.<p>
584      * @param direct If true, restrict the properties returned to those directly
585      * associated with this class.
586      * @return An iteration of the properties that are associated with this class
587      * by their domain.
588      */

589     public ExtendedIterator listDeclaredProperties( boolean direct ) {
590         // first collect the candidate properties
591
Set candSet = new HashSet();
592
593         // if the attached model does inference, it will potentially find more of these
594
// than a non-inference model
595
for (Iterator i = listAllProperties(); i.hasNext(); ) {
596             candSet.add( ((Statement) i.next()).getSubject().as( Property.class ) );
597         }
598
599         // now we iterate over the candidates and check that they match all domain constraints
600
List cands = new ArrayList();
601         cands.addAll( candSet );
602         for (int j = cands.size() -1; j >= 0; j--) {
603             Property cand = (Property) cands.get( j );
604             if (!hasDeclaredProperty( cand, direct )) {
605                 cands.remove( j );
606             }
607         }
608
609         // return the results, using the ont property facet
610
return WrappedIterator.create( cands.iterator() )
611                               .mapWith( new AsMapper( OntProperty.class ) );
612     }
613
614
615     /**
616      * <p>Answer true if the given property is one of the declared properties
617      * of this class. For details, see {@link #listDeclaredProperties(boolean)}.</p>
618      * @param p A property to test
619      * @param direct If true, only direct associations between classes and properties
620      * are considered
621      * @return True if <code>p</code> is one of the declared properties of
622      * this class
623      */

624     public boolean hasDeclaredProperty( Property p, boolean direct ) {
625         return testDomain( p, direct );
626     }
627
628
629     /**
630      * <p>Answer an iterator over the individuals in the model that have this
631      * class among their types.<p>
632      *
633      * @return An iterator over those instances that have this class as one of
634      * the classes to which they belong
635      */

636     public ExtendedIterator listInstances() {
637         return UniqueExtendedIterator.create(
638                         getModel()
639                             .listStatements( null, RDF.type, this )
640                             .mapWith( new SubjectAsMapper( Individual.class ) )
641                    );
642     }
643
644
645     /**
646      * <p>Answer a new individual that has this class as its <code>rdf:type</code></p>
647      * @return A new anonymous individual that is an instance of this class
648      */

649     public Individual createIndividual() {
650         return ((OntModel) getModel()).createIndividual( this );
651     }
652
653
654     /**
655      * <p>Answer a new individual that has this class as its <code>rdf:type</code></p>
656      * @param uri The URI of the new individual
657      * @return A new named individual that is an instance of this class
658      */

659     public Individual createIndividual( String JavaDoc uri ) {
660         return ((OntModel) getModel()).createIndividual( uri, this );
661     }
662
663
664     /**
665      * <p>Answer true if this class is one of the roots of the class hierarchy.
666      * This will be true if either (i) this class has <code>owl:Thing</code>
667      * (or <code>daml:Thing</code>) as a direct super-class, or (ii) it has
668      * no declared super-classes (including anonymous class expressions).</p>
669      * @return True if this class is the root of the class hierarchy in the
670      * model it is attached to
671      */

672     public boolean isHierarchyRoot() {
673         // sanity check - :Nothing is never a root class
674
if (equals( getProfile().NOTHING() )) {
675             return false;
676         }
677
678         // the only super-classes of a root class are the various aliases
679
// of Top, or itself
680
ExtendedIterator i = null;
681         try {
682             i = listSuperClasses( true );
683
684             while (i.hasNext()) {
685                 Resource sup = (Resource) i.next();
686                 if (!(sup.equals( getProfile().THING() ) ||
687                       sup.equals( RDFS.Resource ) ||
688                       sup.equals( this )))
689                 {
690                     // a super that indicates this is not a root class
691
return false;
692                 }
693             }
694         }
695         finally {
696             i.close();
697         }
698
699         return true;
700     }
701
702
703     // access to facets
704
/**
705      * <p>Answer a view of this class as an enumerated class</p>
706      * @return This class, but viewed as an EnumeratedClass node
707      * @exception ConversionException if the class cannot be converted to an enumerated class
708      * given the lanuage profile and the current state of the underlying model.
709      */

710     public EnumeratedClass asEnumeratedClass() {
711         return (EnumeratedClass) as( EnumeratedClass.class );
712     }
713
714     /**
715      * <p>Answer a view of this class as a union class</p>
716      * @return This class, but viewed as a UnionClass node
717      * @exception ConversionException if the class cannot be converted to a union class
718      * given the lanuage profile and the current state of the underlying model.
719      */

720     public UnionClass asUnionClass() {
721         return (UnionClass) as( UnionClass.class );
722     }
723
724     /**
725      * <p>Answer a view of this class as an intersection class</p>
726      * @return This class, but viewed as an IntersectionClass node
727      * @exception ConversionException if the class cannot be converted to an intersection class
728      * given the lanuage profile and the current state of the underlying model.
729      */

730     public IntersectionClass asIntersectionClass() {
731         return (IntersectionClass) as( IntersectionClass.class );
732     }
733
734     /**
735      * <p>Answer a view of this class as a complement class</p>
736      * @return This class, but viewed as a ComplementClass node
737      * @exception ConversionException if the class cannot be converted to a complement class
738      * given the lanuage profile and the current state of the underlying model.
739      */

740     public ComplementClass asComplementClass() {
741         return (ComplementClass) as( ComplementClass.class );
742     }
743
744     /**
745      * <p>Answer a view of this class as a restriction class expression</p>
746      * @return This class, but viewed as a Restriction node
747      * @exception ConversionException if the class cannot be converted to a restriction
748      * given the lanuage profile and the current state of the underlying model.
749      */

750     public Restriction asRestriction() {
751         return (Restriction) as( Restriction.class );
752     }
753
754
755     // sub-type testing
756

757     /**
758      * <p>Answer true if this class is an enumerated class expression</p>
759      * @return True if this is an enumerated class expression
760      */

761     public boolean isEnumeratedClass() {
762         checkProfile( getProfile().ONE_OF(), "ONE_OF" );
763         return hasProperty( getProfile().ONE_OF() );
764     }
765
766     /**
767      * <p>Answer true if this class is a union class expression</p>
768      * @return True if this is a union class expression
769      */

770     public boolean isUnionClass() {
771         checkProfile( getProfile().UNION_OF(), "UNION_OF" );
772         return hasProperty( getProfile().UNION_OF() );
773     }
774
775     /**
776      * <p>Answer true if this class is an intersection class expression</p>
777      * @return True if this is an intersection class expression
778      */

779     public boolean isIntersectionClass() {
780         checkProfile( getProfile().INTERSECTION_OF(), "INTERSECTION_OF" );
781         return hasProperty( getProfile().INTERSECTION_OF() );
782     }
783
784     /**
785      * <p>Answer true if this class is a complement class expression</p>
786      * @return True if this is a complement class expression
787      */

788     public boolean isComplementClass() {
789         checkProfile( getProfile().COMPLEMENT_OF(), "COMPLEMENT_OF" );
790         return hasProperty( getProfile().COMPLEMENT_OF() );
791     }
792
793     /**
794      * <p>Answer true if this class is a property restriction</p>
795      * @return True if this is a restriction
796      */

797     public boolean isRestriction() {
798         checkProfile( getProfile().RESTRICTION(), "RESTRICTION" );
799         return hasProperty( getProfile().ON_PROPERTY() ) ||
800                hasProperty( RDF.type, getProfile().RESTRICTION() );
801     }
802
803
804     // conversion operations
805

806     /**
807      * <p>Answer a view of this class as an enumeration of the given individuals.</p>
808      * @param individuals A list of the individuals that will comprise the permitted values of this
809      * class converted to an enumeration
810      * @return This ontology class, converted to an enumeration of the given individuals
811      */

812     public EnumeratedClass convertToEnumeratedClass( RDFList individuals ) {
813         setPropertyValue( getProfile().ONE_OF(), "ONE_OF", individuals );
814         return (EnumeratedClass) as( EnumeratedClass.class );
815     }
816
817     /**
818      * <p>Answer a view of this class as an intersection of the given classes.</p>
819      * @param classes A list of the classes that will comprise the operands of the intersection
820      * @return This ontology class, converted to an intersection of the given classes
821      */

822     public IntersectionClass convertToIntersectionClass( RDFList classes ) {
823         setPropertyValue( getProfile().INTERSECTION_OF(), "INTERSECTION_OF", classes );
824         return (IntersectionClass) as( IntersectionClass.class );
825     }
826
827     /**
828      * <p>Answer a view of this class as a union of the given classes.</p>
829      * @param classes A list of the classes that will comprise the operands of the union
830      * @return This ontology class, converted to an union of the given classes
831      */

832     public UnionClass convertToUnionClass( RDFList classes ) {
833         setPropertyValue( getProfile().UNION_OF(), "UNION_OF", classes );
834         return (UnionClass) as( UnionClass.class );
835     }
836
837     /**
838      * <p>Answer a view of this class as an complement of the given class.</p>
839      * @param cls An ontology classs that will be operand of the complement
840      * @return This ontology class, converted to an complement of the given class
841      */

842     public ComplementClass convertToComplementClass( Resource cls ) {
843         setPropertyValue( getProfile().COMPLEMENT_OF(), "COMPLEMENT_OF", cls );
844         return (ComplementClass) as( ComplementClass.class );
845     }
846
847     /**
848      * <p>Answer a view of this class as an resriction on the given property.</p>
849      * @param prop A property this is the subject of a property restriction class expression
850      * @return This ontology class, converted to a restriction on the given property
851      */

852     public Restriction convertToRestriction( Property prop ) {
853         if (!hasRDFType( getProfile().RESTRICTION(), "RESTRICTION", false )) {
854             setRDFType( getProfile().RESTRICTION() );
855         }
856         setPropertyValue( getProfile().ON_PROPERTY(), "ON_PROPERTY", prop );
857         return (Restriction) as( Restriction.class );
858     }
859
860
861     // Internal implementation methods
862
//////////////////////////////////
863

864
865     private void collectProperty( Property p, Set props, OntModel m ) {
866         // make sure that the property is attached to the right model
867
props.add( m.getProperty( p.getURI() ) );
868     }
869
870     /**
871      * <p>Answer true if this class has the given class as a direct super-class, without using
872      * extra help from the reasoner.</p>
873      * @param cls The class to test
874      * @return True if the cls is a direct super-class of this class
875      */

876     protected boolean hasSuperClassDirect(Resource cls) {
877         // we manually compute the maximal lower elements - this could be expensive in general
878
//return ResourceUtils.maximalLowerElements( listSuperClasses(), getProfile().SUB_CLASS_OF(), false ).contains( cls );
879

880         ExtendedIterator i = listDirectPropertyValues( getProfile().SUB_CLASS_OF(), "subClassOf", OntClass.class,
881                                                        getProfile().SUB_CLASS_OF(), true, false );
882         try {
883             while (i.hasNext()) {
884                 if (cls.equals( i.next() )) {
885                     return true;
886                 }
887             }
888         }
889         finally {
890             i.close();
891         }
892
893         return false;
894     }
895
896
897     /**
898      * <p>Answer true if this class lies with the domain of p<p>
899      * @param p
900      * @param direct
901      * @return
902      */

903     protected boolean testDomain( Property p, boolean direct ) {
904         // we ignore any property in the DAML, OWL, etc namespace
905
String JavaDoc namespace = p.getNameSpace();
906         for (int i = 0; i < IGNORE_NAMESPACES.length; i++) {
907             if (namespace.equals( IGNORE_NAMESPACES[i] )) {
908                 return false;
909             }
910         }
911
912         // check for global props, that have no specific domain constraint
913
boolean isGlobal = true;
914
915         // flag for detecting the direct case
916
boolean seenDirect = false;
917
918         for (StmtIterator i = getModel().listStatements( p, getProfile().DOMAIN(), (RDFNode) null ); i.hasNext(); ) {
919             Resource domain = i.nextStatement().getResource();
920
921             // there are some well-known values we ignore
922
if (!(domain.equals( getProfile().THING() ) || domain.equals( RDFS.Resource ))) {
923                 // not a generic domain
924
isGlobal = false;
925
926                 if (domain.equals( this )) {
927                     // if this class is actually in the domain (as opposed to one of this class's
928
// super-classes), then we've detected the direct property case
929
seenDirect = true;
930                 }
931                 else if (!canProveSuperClass( domain )) {
932                     // there is a class in the domain of p that is not a super-class of this class
933
return false;
934                 }
935             }
936         }
937
938         if (direct) {
939             // if we're looking for direct props, we must either have seen the direct case
940
// or it's a global prop and this is a root class
941
return seenDirect || (isGlobal && isHierarchyRoot());
942         }
943         else {
944             // not direct, we must either found a global or a super-class prop
945
// otherwise the 'return false' above would have kicked in
946
return true;
947         }
948     }
949
950
951     /**
952      * <p>Answer an iterator over all of the properties in this model
953      * @return
954      */

955     protected ExtendedIterator listAllProperties() {
956         OntModel mOnt = (OntModel) getModel();
957         Profile prof = mOnt.getProfile();
958
959         ExtendedIterator pi = mOnt.listStatements( null, RDF.type, getProfile().PROPERTY() );
960
961         // check reasoner capabilities - major performance improvement for inf models
962
if (mOnt.getReasoner() != null) {
963             Model caps = mOnt.getReasoner().getReasonerCapabilities();
964             if (caps.contains( null, ReasonerVocabulary.supportsP, OWL.ObjectProperty) ||
965                 caps.contains( null, ReasonerVocabulary.supportsP, DAML_OIL.ObjectProperty))
966             {
967                 // we conclude that the reasoner can do the necessary work to infer that
968
// all owl:ObjectProperty, owl:DatatypeProperty, etc, are rdf:Property resources
969
return pi;
970             }
971         }
972
973         // otherwise, we manually check the other property types
974
if (prof.OBJECT_PROPERTY() != null) {
975             pi = pi.andThen( mOnt.listStatements( null, RDF.type, prof.OBJECT_PROPERTY() ) );
976         }
977         if (prof.DATATYPE_PROPERTY() != null) {
978             pi = pi.andThen( mOnt.listStatements( null, RDF.type, prof.DATATYPE_PROPERTY() ) );
979         }
980         if (prof.FUNCTIONAL_PROPERTY() != null) {
981             pi = pi.andThen( mOnt.listStatements( null, RDF.type, prof.FUNCTIONAL_PROPERTY() ) );
982         }
983         if (prof.INVERSE_FUNCTIONAL_PROPERTY() != null) {
984             pi = pi.andThen( mOnt.listStatements( null, RDF.type, prof.INVERSE_FUNCTIONAL_PROPERTY() ) );
985         }
986         if (prof.SYMMETRIC_PROPERTY() != null) {
987             pi = pi.andThen( mOnt.listStatements( null, RDF.type, prof.SYMMETRIC_PROPERTY() ) );
988         }
989         if (prof.TRANSITIVE_PROPERTY() != null) {
990             pi = pi.andThen( mOnt.listStatements( null, RDF.type, prof.TRANSITIVE_PROPERTY() ) );
991         }
992         if (prof.ANNOTATION_PROPERTY() != null) {
993             pi = pi.andThen( mOnt.listStatements( null, RDF.type, prof.ANNOTATION_PROPERTY() ) );
994         }
995
996         return pi;
997     }
998
999     /**
1000     * <p>Answer true if we can demonstrate that this class has the given super-class.
1001     * If this model has a reasoner, this is equivalent to asking if the sub-class
1002     * relation holds. Otherwise, we simulate basic reasoning by searching upwards
1003     * through the class hierarchy.</p>
1004     * @param sup A super-class to test for
1005     * @return True if we can show that sup is a super-class of thsi class
1006     */

1007    protected boolean canProveSuperClass( Resource sup ) {
1008        OntModel om = (OntModel) getModel();
1009        if (om.getReasoner() != null) {
1010            if (om.getReasoner()
1011                  .getReasonerCapabilities().contains( null, ReasonerVocabulary.supportsP, RDFS.subClassOf ))
1012            {
1013                // this reasoner does transitive closure on sub-classes, so we just ask
1014
return hasSuperClass( sup );
1015            }
1016        }
1017
1018        // otherwise, we have to search upwards through the class hierarchy
1019
Set seen = new HashSet();
1020        List queue = new ArrayList();
1021        queue.add( this );
1022
1023        while (!queue.isEmpty()) {
1024            OntClass c = (OntClass) queue.remove( 0 );
1025            if (!seen.contains( c )) {
1026                seen.add( c );
1027
1028                if (c.equals( sup )) {
1029                    // found the super class
1030
return true;
1031                }
1032                else {
1033                    // queue the supers
1034
for (Iterator i = c.listSuperClasses(); i.hasNext(); ) {
1035                        queue.add( i.next() );
1036                    }
1037                }
1038            }
1039        }
1040
1041        // to get here, we didn't find the class we were looking for
1042
return false;
1043    }
1044
1045    //==============================================================================
1046
// Inner class definitions
1047
//==============================================================================
1048

1049}
1050
1051
1052/*
1053    (c) Copyright 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
1054    All rights reserved.
1055
1056    Redistribution and use in source and binary forms, with or without
1057    modification, are permitted provided that the following conditions
1058    are met:
1059
1060    1. Redistributions of source code must retain the above copyright
1061       notice, this list of conditions and the following disclaimer.
1062
1063    2. Redistributions in binary form must reproduce the above copyright
1064       notice, this list of conditions and the following disclaimer in the
1065       documentation and/or other materials provided with the distribution.
1066
1067    3. The name of the author may not be used to endorse or promote products
1068       derived from this software without specific prior written permission.
1069
1070    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1071    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1072    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1073    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1074    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1075    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1076    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1077    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1078    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1079    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1080*/

1081
1082
Popular Tags