KickJava   Java API By Example, From Geeks To Geeks.

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


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 25-Mar-2003
9  * Filename $RCSfile: OntResourceImpl.java,v $
10  * Revision $Revision: 1.53 $
11  * Release status $State: Exp $
12  *
13  * Last modified on $Date: 2005/04/11 16:40:38 $
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 // Imports
26
///////////////
27
import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
28 import com.hp.hpl.jena.enhanced.*;
29 import com.hp.hpl.jena.graph.*;
30 import com.hp.hpl.jena.shared.*;
31 import com.hp.hpl.jena.ontology.*;
32 import com.hp.hpl.jena.rdf.model.*;
33 import com.hp.hpl.jena.rdf.model.impl.*;
34 import com.hp.hpl.jena.reasoner.*;
35 import com.hp.hpl.jena.reasoner.rulesys.BasicForwardRuleInfGraph;
36 import com.hp.hpl.jena.util.ResourceUtils;
37 import com.hp.hpl.jena.util.iterator.*;
38 import com.hp.hpl.jena.vocabulary.*;
39
40 import java.util.*;
41
42 import org.apache.commons.logging.Log;
43 import org.apache.commons.logging.LogFactory;
44
45
46 /**
47  * <p>
48  * Abstract base class to provide shared implementation for implementations of ontology
49  * resources.
50  * </p>
51  *
52  * @author Ian Dickinson, HP Labs
53  * (<a HREF="mailto:Ian.Dickinson@hp.com" >email</a>)
54  * @version CVS $Id: OntResourceImpl.java,v 1.53 2005/04/11 16:40:38 ian_dickinson Exp $
55  */

56 public class OntResourceImpl
57     extends ResourceImpl
58     implements OntResource
59 {
60     // Constants
61
//////////////////////////////////
62

63     /** List of namespaces that are reserved for known ontology langauges */
64     public static final String JavaDoc[] KNOWN_LANGUAGES = new String JavaDoc[] {OWL.NS,
65                                                                  RDF.getURI(),
66                                                                  RDFS.getURI(),
67                                                                  DAMLVocabulary.NAMESPACE_DAML_2001_03_URI,
68                                                                  XSDDatatype.XSD};
69
70     // Static variables
71
//////////////////////////////////
72

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

78     public static Implementation factory = new Implementation() {
79         public EnhNode wrap( Node n, EnhGraph eg ) {
80             if (canWrap( n, eg )) {
81                 return new OntResourceImpl( n, eg );
82             }
83             else {
84                 throw new ConversionException( "Cannot convert node " + n.toString() + " to OntResource");
85             }
86         }
87
88         public boolean canWrap( Node node, EnhGraph eg ) {
89             // node will support being an OntResource facet if it is a uri or bnode
90
return node.isURI() || node.isBlank();
91         }
92     };
93
94     private static final Log log = LogFactory.getLog( OntResourceImpl.class );
95
96     // Instance variables
97
//////////////////////////////////
98

99     // Constructors
100
//////////////////////////////////
101

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

110     public OntResourceImpl( Node n, EnhGraph g ) {
111         super( n, g );
112     }
113
114
115     // External signature methods
116
//////////////////////////////////
117

118     /**
119      * <p>
120      * Answer the ontology language profile that governs the ontology model to which
121      * this ontology resource is attached.
122      * </p>
123      *
124      * @return The language profile for this ontology resource
125      */

126     public Profile getProfile() {
127         return ((OntModel) getModel()).getProfile();
128     }
129
130     /**
131      * <p>Answer true if this resource is a symbol in one of the standard ontology
132      * languages supported by Jena: RDF, RDFS, OWL or DAML+OIL. Since these languages
133      * have restricted namespaces, this check is simply a convenient way of testing whether
134      * this resource is in one of those pre-declared namespaces.</p>
135      * @return True if this is a term in the language namespace for OWL, RDF, RDFS or DAML+OIL.
136      */

137     public boolean isOntLanguageTerm() {
138         if (!isAnon()) {
139             for (int i = 0; i < KNOWN_LANGUAGES.length; i++) {
140                 if (getURI().startsWith( KNOWN_LANGUAGES[i] )) {
141                     return true;
142                 }
143             }
144         }
145         return false;
146     }
147
148
149     // sameAs
150

151     /**
152      * <p>Assert equivalence between the given resource and this resource. Any existing
153      * statements for <code>sameAs</code> will be removed.</p>
154      * @param res The resource that is declared to be the same as this resource
155      * @exception OntProfileException If the {@link Profile#SAME_AS()} property is not supported in the current language profile.
156      */

157     public void setSameAs( Resource res ) {
158         setPropertyValue( getProfile().SAME_AS(), "SAME_AS", res );
159     }
160
161     /**
162      * <p>Add a resource that is declared to be equivalent to this resource.</p>
163      * @param res A resource that declared to be the same as this resource
164      * @exception OntProfileException If the {@link Profile#SAME_AS()} property is not supported in the current language profile.
165      */

166     public void addSameAs( Resource res ) {
167         addPropertyValue( getProfile().SAME_AS(), "SAME_AS", res );
168     }
169
170     /**
171      * <p>Answer a resource that is declared to be the same as this resource. If there is
172      * more than one such resource, an arbitrary selection is made.</p>
173      * @return res An ont resource that declared to be the same as this resource
174      * @exception OntProfileException If the {@link Profile#SAME_AS()} property is not supported in the current language profile.
175      */

176     public OntResource getSameAs() {
177         return objectAsResource( getProfile().SAME_AS(), "SAME_AS" );
178     }
179
180     /**
181      * <p>Answer an iterator over all of the resources that are declared to be the same as
182      * this resource. Each elemeent of the iterator will be an {@link OntResource}.</p>
183      * @return An iterator over the resources equivalent to this resource.
184      * @exception OntProfileException If the {@link Profile#SAME_AS()} property is not supported in the current language profile.
185      */

186     public ExtendedIterator listSameAs() {
187         return listAs( getProfile().SAME_AS(), "SAME_AS", OntResource.class );
188     }
189
190     /**
191      * <p>Answer true if this resource is the same as the given resource.</p>
192      * @param res A resource to test against
193      * @return True if the resources are declared the same via a <code>sameAs</code> statement.
194      */

195     public boolean isSameAs( Resource res ) {
196         return hasPropertyValue( getProfile().SAME_AS(), "SAME_AS", res );
197     }
198
199     /**
200      * <p>Remove the statement that this resource is the same as the given resource. If this statement
201      * is not true of the current model, nothing happens.</p>
202      * @param res A resource that may be declared to be the sameAs this resource
203      */

204     public void removeSameAs( Resource res ) {
205         removePropertyValue( getProfile().SAME_AS(), "SAME_AS", res );
206     }
207
208     // differentFrom
209

210     /**
211      * <p>Assert that the given resource and this resource are distinct. Any existing
212      * statements for <code>differentFrom</code> will be removed.</p>
213      * @param res The resource that is declared to be distinct from this resource
214      * @exception OntProfileException If the {@link Profile#DIFFERENT_FROM()} property is not supported in the current language profile.
215      */

216     public void setDifferentFrom( Resource res ) {
217         setPropertyValue( getProfile().DIFFERENT_FROM(), "DIFFERENT_FROM", res );
218     }
219
220     /**
221      * <p>Add a resource that is declared to be equivalent to this resource.</p>
222      * @param res A resource that declared to be the same as this resource
223      * @exception OntProfileException If the {@link Profile#DIFFERENT_FROM()} property is not supported in the current language profile.
224      */

225     public void addDifferentFrom( Resource res ) {
226         addPropertyValue( getProfile().DIFFERENT_FROM(), "DIFFERENT_FROM", res );
227     }
228
229     /**
230      * <p>Answer a resource that is declared to be distinct from this resource. If there is
231      * more than one such resource, an arbitrary selection is made.</p>
232      * @return res An ont resource that declared to be different from this resource
233      * @exception OntProfileException If the {@link Profile#DIFFERENT_FROM()} property is not supported in the current language profile.
234      */

235     public OntResource getDifferentFrom() {
236         return objectAsResource( getProfile().DIFFERENT_FROM(), "DIFFERENT_FROM" );
237     }
238
239     /**
240      * <p>Answer an iterator over all of the resources that are declared to be different from
241      * this resource. Each elemeent of the iterator will be an {@link OntResource}.</p>
242      * @return An iterator over the resources different from this resource.
243      * @exception OntProfileException If the {@link Profile#DIFFERENT_FROM()} property is not supported in the current language profile.
244      */

245     public ExtendedIterator listDifferentFrom() {
246         return listAs( getProfile().DIFFERENT_FROM(), "DIFFERENT_FROM", OntResource.class );
247     }
248
249     /**
250      * <p>Answer true if this resource is different from the given resource.</p>
251      * @param res A resource to test against
252      * @return True if the resources are declared to be distinct via a <code>differentFrom</code> statement.
253      */

254     public boolean isDifferentFrom( Resource res ) {
255         return hasPropertyValue( getProfile().DIFFERENT_FROM(), "DIFFERENT_FROM", res );
256     }
257
258     /**
259      * <p>Remove the statement that this resource is different the given resource. If this statement
260      * is not true of the current model, nothing happens.</p>
261      * @param res A resource that may be declared to be differentFrom this resource
262      */

263     public void removeDifferentFrom( Resource res ) {
264         removePropertyValue( getProfile().DIFFERENT_FROM(), "DIFFERENT_FROM", res );
265     }
266
267     // seeAlso
268

269     /**
270      * <p>Assert that the given resource provides additional information about the definition of this resource</p>
271      * @param res A resource that can provide additional information about this resource
272      * @exception OntProfileException If the {@link Profile#SEE_ALSO()} property is not supported in the current language profile.
273      */

274     public void setSeeAlso( Resource res ) {
275         setPropertyValue( getProfile().SEE_ALSO(), "SEE_ALSO", res );
276     }
277
278     /**
279      * <p>Add a resource that is declared to provided additional information about the definition of this resource</p>
280      * @param res A resource that provides extra information on this resource
281      * @exception OntProfileException If the {@link Profile#SEE_ALSO()} property is not supported in the current language profile.
282      */

283     public void addSeeAlso( Resource res ) {
284         addPropertyValue( getProfile().SEE_ALSO(), "SEE_ALSO", res );
285     }
286
287     /**
288      * <p>Answer a resource that provides additional information about this resource. If more than one such resource
289      * is defined, make an arbitrary choice.</p>
290      * @return res A resource that provides additional information about this resource
291      * @exception OntProfileException If the {@link Profile#SEE_ALSO()} property is not supported in the current language profile.
292      */

293     public Resource getSeeAlso() {
294         return objectAsResource( getProfile().SEE_ALSO(), "SEE_ALSO" );
295     }
296
297     /**
298      * <p>Answer an iterator over all of the resources that are declared to provide addition
299      * information about this resource.</p>
300      * @return An iterator over the resources providing additional definition on this resource.
301      * @exception OntProfileException If the {@link Profile#SEE_ALSO()} property is not supported in the current language profile.
302      */

303     public ExtendedIterator listSeeAlso() {
304         checkProfile( getProfile().SEE_ALSO(), "SEE_ALSO" );
305         return WrappedIterator.create( listProperties( getProfile().SEE_ALSO() ) )
306                .mapWith( new ObjectMapper() );
307     }
308
309     /**
310      * <p>Answer true if this resource has the given resource as a source of additional information.</p>
311      * @param res A resource to test against
312      * @return True if the <code>res</code> provides more information on this resource.
313      */

314     public boolean hasSeeAlso( Resource res ) {
315         return hasPropertyValue( getProfile().SEE_ALSO(), "SEE_ALSO", res );
316     }
317
318     /**
319      * <p>Remove the statement indicating the given resource as a source of additional information
320      * about this resource. If this statement
321      * is not true of the current model, nothing happens.</p>
322      * @param res A resource that may be declared to provide additional information about this resource
323      */

324     public void removeSeeAlso( Resource res ) {
325         removePropertyValue( getProfile().SEE_ALSO(), "SEE_ALSO", res );
326     }
327
328     // is defined by
329

330     /**
331      * <p>Assert that the given resource provides a source of definitions about this resource. Any existing
332      * statements for <code>isDefinedBy</code> will be removed.</p>
333      * @param res The resource that is declared to be a definition of this resource.
334      * @exception OntProfileException If the {@link Profile#IS_DEFINED_BY()} property is not supported in the current language profile.
335      */

336     public void setIsDefinedBy( Resource res ) {
337         setPropertyValue( getProfile().IS_DEFINED_BY(), "IS_DEFINED_BY", res );
338     }
339
340     /**
341      * <p>Add a resource that is declared to provide a definition of this resource.</p>
342      * @param res A defining resource
343      * @exception OntProfileException If the {@link Profile#IS_DEFINED_BY()} property is not supported in the current language profile.
344      */

345     public void addIsDefinedBy( Resource res ) {
346         addPropertyValue( getProfile().IS_DEFINED_BY(), "IS_DEFINED_BY", res );
347     }
348
349     /**
350      * <p>Answer a resource that is declared to provide a definition of this resource. If there is
351      * more than one such resource, an arbitrary selection is made.</p>
352      * @return res An ont resource that is declared to provide a definition of this resource
353      * @exception OntProfileException If the {@link Profile#IS_DEFINED_BY()} property is not supported in the current language profile.
354      */

355     public Resource getIsDefinedBy() {
356         return objectAsResource( getProfile().IS_DEFINED_BY(), "IS_DEFINED_BY" );
357     }
358
359     /**
360      * <p>Answer an iterator over all of the resources that are declared to define
361      * this resource. </p>
362      * @return An iterator over the resources defining this resource.
363      * @exception OntProfileException If the {@link Profile#IS_DEFINED_BY()} property is not supported in the current language profile.
364      */

365     public ExtendedIterator listIsDefinedBy() {
366         checkProfile( getProfile().IS_DEFINED_BY(), "IS_DEFINED_BY" );
367         return WrappedIterator.create( listProperties( getProfile().IS_DEFINED_BY() ) )
368                .mapWith( new ObjectMapper() );
369     }
370
371     /**
372      * <p>Answer true if this resource is defined by the given resource.</p>
373      * @param res A resource to test against
374      * @return True if <code>res</code> defines this resource.
375      */

376     public boolean isDefinedBy( Resource res ) {
377         return hasPropertyValue( getProfile().IS_DEFINED_BY(), "IS_DEFINED_BY", res );
378     }
379
380     /**
381      * <p>Remove the statement that this resource is defined by the given resource. If this statement
382      * is not true of the current model, nothing happens.</p>
383      * @param res A resource that may be declared to define this resource
384      */

385     public void removeDefinedBy( Resource res ) {
386         removePropertyValue( getProfile().IS_DEFINED_BY(), "IS_DEFINED_BY", res );
387     }
388
389
390     // version info
391

392     /**
393      * <p>Assert that the given string is the value of the version info for this resource. Any existing
394      * statements for <code>versionInfo</code> will be removed.</p>
395      * @param info The version information for this resource
396      * @exception OntProfileException If the {@link Profile#VERSION_INFO()} property is not supported in the current language profile.
397      */

398     public void setVersionInfo( String JavaDoc info ) {
399         checkProfile( getProfile().VERSION_INFO(), "VERSION_INFO" );
400         removeAll( getProfile().VERSION_INFO() );
401         addVersionInfo( info );
402     }
403
404     /**
405      * <p>Add the given version information to this resource.</p>
406      * @param info A version information string for this resource
407      * @exception OntProfileException If the {@link Profile#VERSION_INFO()} property is not supported in the current language profile.
408      */

409     public void addVersionInfo( String JavaDoc info ) {
410         checkProfile( getProfile().VERSION_INFO(), "VERSION_INFO" );
411         addProperty( getProfile().VERSION_INFO(), getModel().createLiteral( info ) );
412     }
413
414     /**
415      * <p>Answer the version information string for this object. If there is
416      * more than one such resource, an arbitrary selection is made.</p>
417      * @return A version info string
418      * @exception OntProfileException If the {@link Profile#VERSION_INFO()} property is not supported in the current language profile.
419      */

420     public String JavaDoc getVersionInfo() {
421         checkProfile( getProfile().VERSION_INFO(), "VERSION_INFO" );
422         try {
423             return getRequiredProperty( getProfile().VERSION_INFO() ).getString();
424         }
425         catch (PropertyNotFoundException ignore) {
426             return null;
427         }
428     }
429
430     /**
431      * <p>Answer an iterator over all of the version info strings for this resource.</p>
432      * @return An iterator over the version info strings for this resource.
433      * @exception OntProfileException If the {@link Profile#VERSION_INFO()} property is not supported in the current language profile.
434      */

435     public ExtendedIterator listVersionInfo() {
436         checkProfile( getProfile().VERSION_INFO(), "VERSION_INFO" );
437         return WrappedIterator.create( listProperties( getProfile().VERSION_INFO() ) )
438                .mapWith( new ObjectAsStringMapper() );
439     }
440
441     /**
442      * <p>Answer true if this resource has the given version information</p>
443      * @param info Version information to test for
444      * @return True if this resource has <code>info</code> as version information.
445      */

446     public boolean hasVersionInfo( String JavaDoc info ) {
447         checkProfile( getProfile().VERSION_INFO(), "VERSION_INFO" );
448         return hasProperty( getProfile().VERSION_INFO(), info );
449     }
450
451     /**
452      * <p>Remove the statement that the given string provides version information about
453      * this resource. If this statement
454      * is not true of the current model, nothing happens.</p>
455      * @param info A version information string to be removed
456      */

457     public void removeVersionInfo( String JavaDoc info ) {
458         checkProfile( getProfile().VERSION_INFO(), "VERSION_INFO" );
459
460         StmtIterator i = getModel().listStatements( this, getProfile().VERSION_INFO(), info );
461         if (i.hasNext()) {
462             i.nextStatement().remove();
463         }
464
465         i.close();
466     }
467
468     // label
469

470     /**
471      * <p>Assert that the given string is the value of the label for this resource. Any existing
472      * statements for <code>label</code> will be removed.</p>
473      * @param label The label for this resource
474      * @param lang The language attribute for this label (EN, FR, etc) or null if not specified.
475      * @exception OntProfileException If the {@link Profile#LABEL()} property is not supported in the current language profile.
476      */

477     public void setLabel( String JavaDoc label, String JavaDoc lang ) {
478         checkProfile( getProfile().LABEL(), "LABEL" );
479         removeAll( getProfile().LABEL() );
480         addLabel( label, lang );
481     }
482
483     /**
484      * <p>Add the given label to this resource.</p>
485      * @param label A label string for this resource
486      * @param lang The language attribute for this label (EN, FR, etc) or null if not specified.
487      * @exception OntProfileException If the {@link Profile#LABEL()} property is not supported in the current language profile.
488      */

489     public void addLabel( String JavaDoc label, String JavaDoc lang ) {
490         addLabel( getModel().createLiteral( label, lang ) );
491     }
492
493     /**
494      * <p>Add the given label to this resource.</p>
495      * @param label The literal label
496      * @exception OntProfileException If the {@link Profile#LABEL()} property is not supported in the current language profile.
497      */

498     public void addLabel( Literal label ) {
499         addPropertyValue( getProfile().LABEL(), "LABEL", label );
500     }
501
502     /**
503      * <p>Answer the label string for this object. If there is
504      * more than one such resource, an arbitrary selection is made.</p>
505      * @param lang The language attribute for the desired label (EN, FR, etc) or null for don't care. Will
506      * attempt to retreive the most specific label matching the given language</p>
507      * @return A label string matching the given language, or null if there is no matching label.
508      * @exception OntProfileException If the {@link Profile#LABEL()} property is not supported in the current language profile.
509      */

510     public String JavaDoc getLabel( String JavaDoc lang ) {
511         checkProfile( getProfile().LABEL(), "LABEL" );
512         if (lang == null || lang.length() == 0) {
513             // don't care which language version we get
514
try {
515                 return getRequiredProperty( getProfile().LABEL() ).getString();
516             }
517             catch (PropertyNotFoundException ignore) {
518                 return null;
519             }
520         }
521         else {
522             // search for the best match for the specified language
523
return selectLang( listProperties( getProfile().LABEL() ), lang );
524         }
525     }
526
527     /**
528      * <p>Answer an iterator over all of the label literals for this resource.</p>
529      * @param lang The language to restrict any label values to, or null to select all languages
530      * @return An iterator over RDF {@link Literal}'s.
531      * @exception OntProfileException If the {@link Profile#LABEL()} property is not supported in the current language profile.
532      */

533     public ExtendedIterator listLabels( String JavaDoc lang ) {
534         checkProfile( getProfile().LABEL(), "LABEL" );
535         return WrappedIterator.create( listProperties( getProfile().LABEL() ) )
536                .filterKeep( new LangTagFilter( lang ) )
537                .mapWith( new ObjectMapper() );
538     }
539
540     /**
541      * <p>Answer true if this resource has the given label</p>
542      * @param label The label to test for
543      * @param lang The optional language tag, or null for don't care.
544      * @return True if this resource has <code>label</code> as a label.
545      */

546     public boolean hasLabel( String JavaDoc label, String JavaDoc lang ) {
547         return hasLabel( getModel().createLiteral( label, lang ) );
548     }
549
550     /**
551      * <p>Answer true if this resource has the given label</p>
552      * @param label The label to test for
553      * @return True if this resource has <code>label</code> as a label.
554      */

555     public boolean hasLabel( Literal label ) {
556         boolean found = false;
557
558         ExtendedIterator i = listLabels( label.getLanguage() );
559         while (!found && i.hasNext()) {
560             found = label.equals( i.next() );
561         }
562
563         i.close();
564         return found;
565     }
566
567     /**
568      * <p>Remove the statement that the given string is a label for
569      * this resource. If this statement
570      * is not true of the current model, nothing happens.</p>
571      * @param label A label string to be removed
572      * @param lang A lang tag
573      */

574     public void removeLabel( String JavaDoc label, String JavaDoc lang ) {
575         removeLabel( getModel().createLiteral( label, lang ) );
576     }
577
578     /**
579      * <p>Remove the statement that the given string is a label for
580      * this resource. If this statement
581      * is not true of the current model, nothing happens.</p>
582      * @param label A label literal to be removed
583      */

584     public void removeLabel( Literal label ) {
585         removePropertyValue( getProfile().LABEL(), "LABEL", label );
586     }
587
588     // comment
589

590     /**
591      * <p>Assert that the given string is the comment on this resource. Any existing
592      * statements for <code>comment</code> will be removed.</p>
593      * @param comment The comment for this resource
594      * @param lang The language attribute for this comment (EN, FR, etc) or null if not specified.
595      * @exception OntProfileException If the {@link Profile#COMMENT()} property is not supported in the current language profile.
596      */

597     public void setComment( String JavaDoc comment, String JavaDoc lang ) {
598         checkProfile( getProfile().COMMENT(), "COMMENT" );
599         removeAll( getProfile().COMMENT() );
600         addComment( comment, lang );
601     }
602
603     /**
604      * <p>Add the given comment to this resource.</p>
605      * @param comment A comment string for this resource
606      * @param lang The language attribute for this comment (EN, FR, etc) or null if not specified.
607      * @exception OntProfileException If the {@link Profile#COMMENT()} property is not supported in the current language profile.
608      */

609     public void addComment( String JavaDoc comment, String JavaDoc lang ) {
610         addComment( getModel().createLiteral( comment, lang ) );
611     }
612
613     /**
614      * <p>Add the given comment to this resource.</p>
615      * @param comment The literal comment
616      * @exception OntProfileException If the {@link Profile#COMMENT()} property is not supported in the current language profile.
617      */

618     public void addComment( Literal comment ) {
619         checkProfile( getProfile().COMMENT(), "COMMENT" );
620         addProperty( getProfile().COMMENT(), comment );
621     }
622
623     /**
624      * <p>Answer the comment string for this object. If there is
625      * more than one such resource, an arbitrary selection is made.</p>
626      * @param lang The language attribute for the desired comment (EN, FR, etc) or null for don't care. Will
627      * attempt to retreive the most specific comment matching the given language</p>
628      * @return A comment string matching the given language, or null if there is no matching comment.
629      * @exception OntProfileException If the {@link Profile#COMMENT()} property is not supported in the current language profile.
630      */

631     public String JavaDoc getComment( String JavaDoc lang ) {
632         checkProfile( getProfile().COMMENT(), "COMMENT" );
633         if (lang == null) {
634             // don't care which language version we get
635
try {
636                 return getRequiredProperty( getProfile().COMMENT() ).getString();
637             }
638             catch (PropertyNotFoundException ignore) {
639                 // no comment :-)
640
return null;
641             }
642         }
643         else {
644             // search for the best match for the specified language
645
return selectLang( listProperties( getProfile().COMMENT() ), lang );
646         }
647     }
648
649     /**
650      * <p>Answer an iterator over all of the comment literals for this resource.</p>
651      * @return An iterator over RDF {@link Literal}'s.
652      * @exception OntProfileException If the {@link Profile#COMMENT()} property is not supported in the current language profile.
653      */

654     public ExtendedIterator listComments( String JavaDoc lang ) {
655         checkProfile( getProfile().COMMENT(), "COMMENT" );
656         return WrappedIterator.create( listProperties( getProfile().COMMENT() ) )
657                .filterKeep( new LangTagFilter( lang ) )
658                .mapWith( new ObjectMapper() );
659     }
660
661     /**
662      * <p>Answer true if this resource has the given comment.</p>
663      * @param comment The comment to test for
664      * @param lang The optional language tag, or null for don't care.
665      * @return True if this resource has <code>comment</code> as a comment.
666      */

667     public boolean hasComment( String JavaDoc comment, String JavaDoc lang ) {
668         return hasComment( getModel().createLiteral( comment, lang ) );
669     }
670
671     /**
672      * <p>Answer true if this resource has the given comment.</p>
673      * @param comment The comment to test for
674      * @return True if this resource has <code>comment</code> as a comment.
675      */

676     public boolean hasComment( Literal comment ) {
677         boolean found = false;
678
679         ExtendedIterator i = listComments( comment.getLanguage() );
680         while (!found && i.hasNext()) {
681             found = comment.equals( i.next() );
682         }
683
684         i.close();
685         return found;
686     }
687
688     /**
689      * <p>Remove the statement that the given string is a comment on
690      * this resource. If this statement
691      * is not true of the current model, nothing happens.</p>
692      * @param comment A comment string to be removed
693      * @param lang A lang tag
694      */

695     public void removeComment( String JavaDoc comment, String JavaDoc lang ) {
696         removeComment( getModel().createLiteral( comment, lang ) );
697     }
698
699     /**
700      * <p>Remove the statement that the given string is a comment on
701      * this resource. If this statement
702      * is not true of the current model, nothing happens.</p>
703      * @param comment A comment literal to be removed
704      */

705     public void removeComment( Literal comment ) {
706         removePropertyValue( getProfile().COMMENT(), "COMMENT", comment );
707     }
708
709
710     // rdf:type
711

712     /**
713      * <p>Set the RDF type (ie the class) for this resource, replacing any
714      * existing <code>rdf:type</code> property. Any existing statements for the RDF type
715      * will first be removed.</p>
716      *
717      * @param cls The RDF resource denoting the new value for the <code>rdf:type</code> property,
718      * which will replace any existing type property.
719      */

720     public void setRDFType( Resource cls ) {
721         setPropertyValue( RDF.type, "rdf:type", cls );
722     }
723
724     /**
725      * <p>Add the given class as one of the <code>rdf:type</code>'s for this resource.</p>
726      *
727      * @param cls An RDF resource denoting a new value for the <code>rdf:type</code> property.
728      */

729     public void addRDFType( Resource cls ) {
730         addPropertyValue( RDF.type, "rdf:type", cls );
731     }
732
733     /**
734      * <p>
735      * Answer the <code>rdf:type</code> (ie the class) of this resource. If there
736      * is more than one type for this resource, the return value will be one of
737      * the values, but it is not specified which one (nor that it will consistently
738      * be the same one each time). Equivalent to <code>getRDFType( false )</code>.
739      * </p>
740      *
741      * @return A resource that is the rdf:type for this resource, or one of them if
742      * more than one is defined.
743      */

744     public Resource getRDFType() {
745         return getRDFType( false );
746     }
747
748     /**
749      * <p>
750      * Answer the <code>rdf:type</code> (ie the class) of this resource. If there
751      * is more than one type for this resource, the return value will be one of
752      * the values, but it is not specified which one (nor that it will consistently
753      * be the same one each time).
754      * </p>
755      *
756      * @param direct If true, only consider the direct types of this resource, and not
757      * the super-classes of the type(s).
758      * @return A resource that is the rdf:type for this resource, or one of them if
759      * more than one is defined.
760      */

761     public Resource getRDFType( boolean direct ) {
762         ExtendedIterator i = null;
763         try {
764             i = listRDFTypes( direct );
765             return i.hasNext() ? (Resource) i.next(): null;
766         }
767         finally {
768             i.close();
769         }
770     }
771
772     /**
773      * <p>
774      * Answer an iterator over the RDF classes to which this resource belongs.
775      * </p>
776      *
777      * @param direct If true, only answer those resources that are direct types
778      * of this resource, not the super-classes of the class etc.
779      * @return An iterator over the set of this resource's classes, each of which
780      * will be a {@link Resource}.
781      */

782     public ExtendedIterator listRDFTypes( boolean direct ) {
783         Iterator i = listDirectPropertyValues( RDF.type, "rdf:type", null, getProfile().SUB_CLASS_OF(), direct, false );
784         ExtendedIterator j = WrappedIterator.create( i );
785
786         // we only want each result once
787
return UniqueExtendedIterator.create( j );
788     }
789
790     /**
791      * <p>
792      * Answer true if this resource is a member of the class denoted by the
793      * given URI.</p>
794      *
795      * @param uri Denotes the URI of a class to which this value may belong
796      * @return True if this resource has the given class as one of its <code>rdf:type</code>'s.
797      */

798     public boolean hasRDFType( String JavaDoc uri ) {
799         return hasRDFType( getModel().getResource( uri ) );
800     }
801
802     /**
803      * <p>
804      * Answer true if this resource is a member of the class denoted by the
805      * given class resource. Includes all available types, so is equivalent to
806      * <code><pre>
807      * hasRDF( ontClass, false );
808      * </pre></code>
809      * </p>
810      *
811      * @param ontClass Denotes a class to which this value may belong
812      * @return True if this resource has the given class as one of its <code>rdf:type</code>'s.
813      */

814     public boolean hasRDFType( Resource ontClass ) {
815         return hasRDFType( ontClass, "unknown", false );
816     }
817
818     /**
819      * <p>
820      * Answer true if this resource is a member of the class denoted by the
821      * given class resource.
822      * </p>
823      *
824      * @param ontClass Denotes a class to which this value may belong
825      * @param direct If true, only consider the direct types of this resource, ignoring
826      * the super-classes of the stated types.
827      * @return True if this resource has the given class as one of its <code>rdf:type</code>'s.
828      */

829     public boolean hasRDFType( Resource ontClass, boolean direct ) {
830         return hasRDFType( ontClass, "unknown", direct );
831     }
832
833     protected boolean hasRDFType( Resource ontClass, String JavaDoc name, boolean direct ) {
834         checkProfile( ontClass, name );
835
836         if (!direct) {
837             // just an ordinary query - we can answer this directly (more efficient)
838
return hasPropertyValue( RDF.type, "rdf:type", ontClass );
839         }
840         else {
841             // need the direct version - not so efficient
842
ExtendedIterator i = null;
843             try {
844                 i = listRDFTypes( true );
845                 while (i.hasNext()) {
846                     if (ontClass.equals( i.next() )) {
847                         return true;
848                     }
849                 }
850
851                 return false;
852             }
853             finally {
854                 i.close();
855             }
856         }
857     }
858
859     /**
860      * <p>Remove the statement that this resource is of the given RDF type. If this statement
861      * is not true of the current model, nothing happens.</p>
862      * @param cls A resource denoting a class that that is to be removed from the classes of this resource
863      */

864     public void removeRDFType( Resource cls ) {
865         removePropertyValue( RDF.type, "rdf:type", cls );
866     }
867
868     // utility methods
869

870     /**
871      * <p>Answer the cardinality of the given property on this resource. The cardinality
872      * is the number of distinct values there are for the property.</p>
873      * @param p A property
874      * @return The cardinality for the property <code>p</code> on this resource, as an
875      * integer greater than or equal to zero.
876      */

877     public int getCardinality( Property p ) {
878         int n = 0;
879         for (Iterator i = UniqueExtendedIterator.create( listPropertyValues( p ) ); i.hasNext(); n++) {
880             i.next();
881         }
882
883         return n;
884     }
885
886
887     /**
888      * <p>
889      * Set the value of the given property of this ontology resource to the given
890      * value, encoded as an RDFNode. Maintains the invariant that there is
891      * at most one value of the property for a given resource, so existing
892      * property values are first removed. To add multiple properties, use
893      * {@link #addProperty( Property, RDFNode ) addProperty}.
894      * </p>
895      *
896      * @param property The property to update
897      * @param value The new value of the property as an RDFNode, or null to
898      * effectively remove this property.
899      */

900     public void setPropertyValue( Property property, RDFNode value ) {
901         // if there is an existing property, remove it
902
removeAll( property );
903
904         // now set the new value
905
if (value != null) {
906             addProperty( property, value );
907         }
908     }
909
910
911     /**
912      * <p>Answer the value of a given RDF property for this DAML value, or null
913      * if it doesn't have one. The value is returned as an RDFNode, from which
914      * the value can be extracted for literals. If there is more than one RDF
915      * statement with the given property for the current value, it is not defined
916      * which of the values will be returned.</p>
917      *
918      * @param property An RDF property
919      * @return An RDFNode whose value is the value, or one of the values, of the
920      * given property. If the property is not defined, or an error occurs,
921      * returns null.
922      */

923     public RDFNode getPropertyValue( Property property ) {
924         try {
925             return getRequiredProperty( property ).getObject();
926         }
927         catch (PropertyNotFoundException ignore) {
928             return null;
929         }
930     }
931
932
933     /**
934      * <p>Answer an iterator over the set of all values for a given RDF property. Each
935      * value in the iterator will be an RDFNode, representing the value (object) of
936      * each statement in the underlying model.</p>
937      *
938      * @param property The property whose values are sought
939      * @return An Iterator over the values of the property
940      */

941     public NodeIterator listPropertyValues( Property property ) {
942         return new NodeIteratorImpl( listProperties( property ).mapWith( new ObjectMapper() ), null );
943     }
944
945     /**
946     * <p>Removes this resource from the ontology by deleting any statements that refer to it,
947     * as either statement-subject or statement-object.
948     * If this resource is a property, this method will <strong>not</strong> remove statements
949     * whose predicate is this property.</p>
950     * <p><strong>Caveat:</strong> Jena RDF models contain statements, not resources <em>per se</em>,
951     * so this method simulates removal of an object by removing all of the statements that have
952     * this resource as subject or object, with one exception. If the resource is referenced
953     * in an RDF List, i.e. as the object of an <code>rdf:first</code> statement in a list cell,
954     * this reference is <strong>not</strong> removed. Removing an arbitrary <code>rdf:first</code>
955     * statement from the midst of a list, without doing other work to repair the list, would
956     * leave an ill-formed list in the model. Therefore, if this resource is known to appear
957     * in a list somewhere in the model, it should be separately deleted from that list before
958     * calling this remove method.
959     * </p>
960     */

961     public void remove() {
962         Set stmts = new HashSet();
963         List lists = new ArrayList();
964         List skip = new ArrayList();
965         Property first = getProfile().FIRST();
966
967         // collect statements mentioning this object
968
for (StmtIterator i = listProperties(); i.hasNext(); stmts.add( i.next() ) );
969         for (StmtIterator i = getModel().listStatements( null, null, this ); i.hasNext(); stmts.add( i.next() ) );
970
971         // check for lists
972
for (Iterator i = stmts.iterator(); i.hasNext(); ) {
973             Statement s = (Statement) i.next();
974             if (s.getPredicate().equals( first ) &&
975                 s.getObject().equals( this )) {
976                 // _this_ is referenced from inside a list
977
// we don't delete this reference, since it would make the list ill-formed
978
log.debug( toString() + " is referened from an RDFList, so will not be fully removed");
979                 skip.add( s );
980             }
981             else if (s.getObject() instanceof Resource){
982                 // check for list-valued properties
983
Resource obj = s.getResource();
984                 if (obj.canAs( RDFList.class )) {
985                     // this value is a list, so we will want to remove all of the elements
986
lists.add( obj );
987                 }
988             }
989         }
990
991         // add in the contents of the lists to the statements to be removed
992
for (Iterator i = lists.iterator(); i.hasNext(); ) {
993             Resource r = (Resource) i.next();
994             stmts.addAll( ((RDFListImpl) r.as( RDFList.class )).collectStatements() );
995         }
996
997         // skip the contents of the skip list
998
stmts.removeAll( skip );
999
1000        // and then remove the remainder
1001
for (Iterator i = stmts.iterator(); i.hasNext(); ((Statement) i.next()).remove() );
1002    }
1003
1004
1005    /**
1006     * <p>Remove the specific RDF property-value pair from this DAML resource.</p>
1007     *
1008     * @param property The property to be removed
1009     * @param value The specific value of the property to be removed
1010     */

1011    public void removeProperty( Property property, RDFNode value ) {
1012        // have to do this in two phases to avoid concurrent modification exception
1013
Set s = new HashSet();
1014        for (StmtIterator i = getModel().listStatements( this, property, value ); i.hasNext(); s.add( i.nextStatement() ) );
1015        for (Iterator i = s.iterator(); i.hasNext(); ((Statement) i.next()).remove() );
1016    }
1017
1018
1019    /**
1020     * <p>Answer a view of this resource as an annotation property</p>
1021     * @return This resource, but viewed as an AnnotationProperty
1022     * @exception ConversionException if the resource cannot be converted to an annotation property
1023     */

1024    public AnnotationProperty asAnnotationProperty() {
1025        return (AnnotationProperty) as( AnnotationProperty.class );
1026    }
1027
1028    /**
1029     * <p>Answer a view of this resource as a property</p>
1030     * @return This resource, but viewed as an OntProperty
1031     * @exception ConversionException if the resource cannot be converted to a property
1032     */

1033    public OntProperty asProperty() {
1034        return (OntProperty) as( OntProperty.class );
1035    }
1036
1037    /**
1038     * <p>Answer a view of this resource as an object property</p>
1039     * @return This resource, but viewed as an ObjectProperty
1040     * @exception ConversionException if the resource cannot be converted to an object property
1041     */

1042    public ObjectProperty asObjectProperty() {
1043        return (ObjectProperty) as( ObjectProperty.class );
1044    }
1045
1046    /**
1047     * <p>Answer a view of this resource as a datatype property</p>
1048     * @return This resource, but viewed as a DatatypeProperty
1049     * @exception ConversionException if the resource cannot be converted to a datatype property
1050     */

1051    public DatatypeProperty asDatatypeProperty() {
1052        return (DatatypeProperty) as( DatatypeProperty.class );
1053    }
1054
1055    /**
1056     * <p>Answer a view of this resource as an individual</p>
1057     * @return This resource, but viewed as an Individual
1058     * @exception ConversionException if the resource cannot be converted to an individual
1059     */

1060    public Individual asIndividual() {
1061        return (Individual) as( Individual.class );
1062    }
1063
1064    /**
1065     * <p>Answer a view of this resource as a class</p>
1066     * @return This resource, but viewed as an OntClass
1067     * @exception ConversionException if the resource cannot be converted to a class
1068     */

1069    public OntClass asClass() {
1070        return (OntClass) as( OntClass.class );
1071    }
1072
1073    /**
1074     * <p>Answer a view of this resource as an ontology description node</p>
1075     * @return This resource, but viewed as an Ontology
1076     * @exception ConversionException if the resource cannot be converted to an ontology description node
1077     */

1078    public Ontology asOntology() {
1079        return (Ontology) as( Ontology.class );
1080    }
1081
1082    /**
1083     * <p>Answer a view of this resource as an 'all different' declaration</p>
1084     * @return This resource, but viewed as an AllDifferent node
1085     * @exception ConversionException if the resource cannot be converted to an all different declaration
1086     */

1087    public AllDifferent asAllDifferent() {
1088        return (AllDifferent) as( AllDifferent.class );
1089    }
1090
1091    /**
1092     * <p>Answer a view of this resource as a data range</p>
1093     * @return This resource, but viewed as a DataRange
1094     * @exception ConversionException if the resource cannot be converted to a data range
1095     */

1096    public DataRange asDataRange() {
1097        return (DataRange) as( DataRange.class );
1098    }
1099
1100
1101    // Conversion test methods
1102

1103    /**
1104     * <p>Answer true if this resource can be viewed as an annotation property</p>
1105     * @return True if this resource can be viewed as an AnnotationProperty
1106     */

1107    public boolean isAnnotationProperty() {
1108        return getProfile().ANNOTATION_PROPERTY() != null && canAs( AnnotationProperty.class );
1109    }
1110
1111    /**
1112     * <p>Answer true if this resource can be viewed as a property</p>
1113     * @return True if this resource can be viewed as an OntProperty
1114     */

1115    public boolean isProperty() {
1116        return canAs( OntProperty.class );
1117    }
1118
1119    /**
1120     * <p>Answer true if this resource can be viewed as an object property</p>
1121     * @return True if this resource can be viewed as an ObjectProperty
1122     */

1123    public boolean isObjectProperty() {
1124        return getProfile().OBJECT_PROPERTY() != null && canAs( ObjectProperty.class );
1125    }
1126
1127    /**
1128     * <p>Answer true if this resource can be viewed as a datatype property</p>
1129     * @return True if this resource can be viewed as a DatatypeProperty
1130     */

1131    public boolean isDatatypeProperty() {
1132        return getProfile().DATATYPE_PROPERTY() != null && canAs( DatatypeProperty.class );
1133    }
1134
1135    /**
1136     * <p>Answer true if this resource can be viewed as an individual</p>
1137     * @return True if this resource can be viewed as an Individual
1138     */

1139    public boolean isIndividual() {
1140        OntModel m = (getModel() instanceof OntModel) ? (OntModel) getModel() : null;
1141        if (m != null) {
1142            if (!(m.getGraph() instanceof BasicForwardRuleInfGraph) ||
1143                m.getProfile().THING() == null) {
1144                // either not using the OWL reasoner, or not using OWL
1145
// look for an rdf:type of this resource that is a class
1146
for (StmtIterator i = listProperties( RDF.type ); i.hasNext(); ) {
1147                    Resource rType = i.nextStatement().getResource();
1148                    for (StmtIterator j = rType.listProperties( RDF.type ); j.hasNext(); ) {
1149                        if (j.nextStatement().getResource().equals( getProfile().CLASS() )) {
1150                            // we have found an rdf:type of the subject that is an owl, rdfs or daml Class
1151
// therefore this is an individual
1152
return true;
1153                        }
1154                    }
1155                }
1156
1157                // apparently not an instance
1158
return false;
1159            }
1160            else {
1161                // using the rule reasoner on an OWL graph, so we can determine
1162
// individuals as those things that have rdf:type owl:Thing
1163
return hasProperty( RDF.type, getProfile().THING() );
1164            }
1165        }
1166
1167        // default - try to convert and return false if fail
1168
return canAs( Individual.class );
1169    }
1170
1171    /**
1172     * <p>Answer true if this resource can be viewed as a class</p>
1173     * @return True if this resource can be viewed as an OntClass
1174     */

1175    public boolean isClass() {
1176        return canAs( OntClass.class );
1177    }
1178
1179    /**
1180     * <p>Answer true if this resource can be viewed as an ontology description node</p>
1181     * @return True if this resource can be viewed as an Ontology
1182     */

1183    public boolean isOntology() {
1184        return getProfile().ONTOLOGY() != null && canAs( Ontology.class );
1185    }
1186
1187    /**
1188     * <p>Answer true if this resource can be viewed as a data range</p>
1189     * @return True if this resource can be viewed as a DataRange
1190     */

1191    public boolean isDataRange() {
1192        return getProfile().DATARANGE() != null && canAs( DataRange.class );
1193    }
1194
1195    /**
1196     * <p>Answer true if this resource can be viewed as an 'all different' declaration</p>
1197     * @return True if this resource can be viewed as an AllDifferent node
1198     */

1199    public boolean isAllDifferent() {
1200        return getProfile().ALL_DIFFERENT() != null && canAs( AllDifferent.class );
1201    }
1202
1203
1204
1205    // Internal implementation methods
1206
//////////////////////////////////
1207

1208
1209    /** Answer true if the node has the given type in the graph */
1210    protected static boolean hasType( Node n, EnhGraph g, Resource type ) {
1211        boolean hasType = false;
1212        ClosableIterator i = g.asGraph().find( n, RDF.type.asNode(), type.asNode() );
1213        hasType = i.hasNext();
1214        i.close();
1215        return hasType;
1216    }
1217
1218    /**
1219     * Throw an exception if a term is not in the profile
1220     * @param term The term being checked
1221     * @param name The name of the term
1222     * @exception ProfileException if term is null (indicating it is not in the profile)
1223     **/

1224    protected void checkProfile( Object JavaDoc term, String JavaDoc name ) {
1225        if (term == null) {
1226            throw new ProfileException( name, getProfile() );
1227        }
1228    }
1229
1230
1231    /**
1232     * <p>Answer the literal with the language tag that best matches the required language</p>
1233     * @param stmts A StmtIterator over the candidates
1234     * @param lang The language we're searching for, assumed non-null.
1235     * @return The literal value that best matches the given language tag, or null if there are no matches
1236     */

1237    protected String JavaDoc selectLang( StmtIterator stmts, String JavaDoc lang ) {
1238        String JavaDoc found = null;
1239
1240        while (stmts.hasNext()) {
1241            RDFNode n = stmts.nextStatement().getObject();
1242
1243            if (n instanceof Literal) {
1244                Literal l = (Literal) n;
1245                String JavaDoc lLang = l.getLanguage();
1246
1247                // is this a better match?
1248
if (lang.equalsIgnoreCase( lLang )) {
1249                    // exact match
1250
found = l.getString();
1251                    break;
1252                }
1253                else if (lLang != null && lLang.length() > 1 && lang.equalsIgnoreCase( lLang.substring( 0, 2 ) )) {
1254                    // partial match - want EN, found EN-GB
1255
// keep searching in case there's a better
1256
found = l.getString();
1257                }
1258                else if (found == null && lLang == null) {
1259                    // found a string with no (i.e. default) language - keep this unless we've got something better
1260
found = l.getString();
1261                }
1262            }
1263        }
1264
1265        stmts.close();
1266        return found;
1267    }
1268
1269    /** Answer true if the desired lang tag matches the target lang tag */
1270    protected boolean langTagMatch( String JavaDoc desired, String JavaDoc target ) {
1271        return (desired == null) ||
1272               (desired.equalsIgnoreCase( target )) ||
1273               (target.length() > desired.length() && desired.equalsIgnoreCase( target.substring( desired.length() ) ));
1274    }
1275
1276    /** Answer the object of a statement with the given property, .as() the given class */
1277    protected Object JavaDoc objectAs( Property p, String JavaDoc name, Class JavaDoc asClass ) {
1278        checkProfile( p, name );
1279        try {
1280            return getRequiredProperty( p ).getObject().as( asClass );
1281        }
1282        catch (PropertyNotFoundException e) {
1283            return null;
1284        }
1285    }
1286
1287
1288    /** Answer the object of a statement with the given property, .as() an OntResource */
1289    protected OntResource objectAsResource( Property p, String JavaDoc name ) {
1290        return (OntResource) objectAs( p, name, OntResource.class );
1291    }
1292
1293
1294    /** Answer the object of a statement with the given property, .as() an OntProperty */
1295    protected OntProperty objectAsProperty( Property p, String JavaDoc name ) {
1296        return (OntProperty) objectAs( p, name, OntProperty.class );
1297    }
1298
1299
1300    /** Answer the int value of a statement with the given property */
1301    protected int objectAsInt( Property p, String JavaDoc name ) {
1302        checkProfile( p, name );
1303        return getRequiredProperty( p ).getInt();
1304    }
1305
1306
1307    /** Answer an iterator for the given property, whose values are .as() some class */
1308    protected ExtendedIterator listAs( Property p, String JavaDoc name, Class JavaDoc cls ) {
1309        checkProfile( p, name );
1310        return WrappedIterator.create( listProperties( p ) ).mapWith( new ObjectAsMapper( cls ) );
1311    }
1312
1313
1314    /** Add the property value, checking that it is supported in the profile */
1315    protected void addPropertyValue( Property p, String JavaDoc name, RDFNode value ) {
1316        checkProfile( p, name );
1317        addProperty( p, value );
1318    }
1319
1320    /** Set the property value, checking that it is supported in the profile */
1321    protected void setPropertyValue( Property p, String JavaDoc name, RDFNode value ) {
1322        checkProfile( p, name );
1323        removeAll( p );
1324        addProperty( p, value );
1325    }
1326
1327    /** Answer true if the given property is defined in the profile, and has the given value */
1328    protected boolean hasPropertyValue( Property p, String JavaDoc name, RDFNode value ) {
1329        checkProfile( p, name );
1330        return hasProperty( p, value );
1331    }
1332
1333    /** Add the given value to a list which is the value of the given property */
1334    protected void addListPropertyValue( Property p, String JavaDoc name, RDFNode value ) {
1335        checkProfile( p, name );
1336
1337        // get the list value
1338
if (hasProperty( p )) {
1339            RDFNode cur = getRequiredProperty( p ).getObject();
1340            if (!cur.canAs( RDFList.class )) {
1341                throw new OntologyException( "Tried to add a value to a list-valued property " + p +
1342                                             " but the current value is not a list: " + cur );
1343            }
1344
1345            RDFList values = (RDFList) cur.as( RDFList.class );
1346
1347            // now add our value to the list
1348
if (!values.contains( value )){
1349                RDFList newValues = values.with( value );
1350
1351                // if the previous values was nil, the return value will be a new list
1352
if (newValues != values) {
1353                    removeAll( p );
1354                    addProperty( p, newValues );
1355                }
1356            }
1357        }
1358        else {
1359            // create a new list to hold the only value we know so far
1360
addProperty( p, ((OntModel) getModel()).createList( new RDFNode[] {value} ) );
1361        }
1362    }
1363
1364    /** Convert this resource to the facet denoted by cls, by adding rdf:type type if necessary */
1365    protected RDFNode convertToType( Resource type, String JavaDoc name, Class JavaDoc cls ) {
1366        checkProfile( type, name );
1367        if (canAs( cls )) {
1368            // don't need to update the model, we already can do the given facet
1369
return as( cls );
1370        }
1371
1372        // we're told that adding this rdf:type will make the as() possible - let's see
1373
addProperty( RDF.type, type );
1374        return as( cls );
1375    }
1376
1377    /**
1378     * <p>Return an iterator of values, respecting the 'direct' modifier</p>
1379     * @param p The property whose values are required
1380     * @param name The short name of the property (for generating error messages)
1381     * @param cls Class object denoting the facet to map the returned values to
1382     * @param orderRel If direct, and we are not using an inference engine, this is the property
1383     * to use to define the maximal lower elements of the partial order
1384     * @param direct If true, only return the direct (adjacent) values
1385     * @param inverse If true, use the inverse of p rather than p
1386     * @return An iterator of nodes that are in relation p to this resource (possibly inverted), which
1387     * have been mapped to the facet denoted by cls.
1388     */

1389    protected ExtendedIterator listDirectPropertyValues( Property p, String JavaDoc name, Class JavaDoc cls, Property orderRel, boolean direct, boolean inverse ) {
1390        Iterator i = null;
1391        checkProfile( p, name );
1392
1393        Property sc = p;
1394
1395        // check for requesting direct versions of these properties
1396
if (direct) {
1397            sc = getModel().getProperty( ReasonerRegistry.makeDirect( sc.getNode() ).getURI() );
1398        }
1399
1400        // determine the subject and object pairs for the list statements calls
1401
Resource subject = inverse ? null : this;
1402        Resource object = inverse ? this : null;
1403        Map1 mapper = inverse ? (Map1) new SubjectAsMapper( cls ) : (Map1) new ObjectAsMapper( cls );
1404
1405        // are we working on an inference graph?
1406
OntModel m = (OntModel) getGraph();
1407        InfGraph ig = null;
1408        if (m.getGraph() instanceof InfGraph) {
1409            ig = (InfGraph) m.getGraph();
1410        }
1411
1412        // can we go direct to the graph?
1413
if (!direct || ((ig != null) && ig.getReasoner().supportsProperty( sc ))) {
1414            // either not direct, or the direct sc property is supported
1415
// ensure we have an extended iterator of statements this rdfs:subClassOf _x
1416
// NB we only want the subjects or objects of the statements
1417
i = getModel().listStatements( subject, sc, object ).mapWith( mapper );
1418        }
1419        else {
1420            i = computeDirectValues( p, orderRel, inverse, subject, object, mapper );
1421        }
1422
1423        return UniqueExtendedIterator.create( i );
1424    }
1425
1426
1427    /**
1428     * <p>In the absence of a reasoner that can compute direct (adjacent) property values,
1429     * we must perform the calculation of the direct values computationally here.</p>
1430     * @param p
1431     * @param orderRel
1432     * @param inverse
1433     * @param subject
1434     * @param object
1435     * @param mapper
1436     * @return
1437     */

1438    private Iterator computeDirectValues( Property p, Property orderRel, boolean inverse, Resource subject, Resource object, Map1 mapper ) {
1439        // graph does not support direct directly
1440
ExtendedIterator j = getModel().listStatements( subject, p, object )
1441                                       .mapWith( mapper );
1442
1443        // collect a list of the candidates
1444
List s = new ArrayList();
1445        for( ; j.hasNext(); s.add( j.next() ) );
1446
1447        // we need to keep this node out of the iterator for now, else it will spoil the maximal
1448
// generator compression (since all the (e.g.) sub-classes will be sub-classes of this node
1449
// and so will be excluded from the maximal lower elements calculation)
1450
ResourceUtils.removeEquiv( s, orderRel, this );
1451        boolean withheld = s.remove( this );
1452
1453        // we now compress the list by reducing all equivalent values to a single representative
1454

1455        // first partition the list by equivalence under orderRel
1456
List partition = ResourceUtils.partition( s, orderRel );
1457        Map equivSets = new HashMap();
1458
1459        // then reduce each part of the partition to a singleton, but remember the others
1460
s.clear();
1461        for (Iterator i = partition.iterator(); i.hasNext(); ) {
1462            List part = (List) i.next();
1463            // if this is a singleton we just add it to the compressed candidates
1464
if (part.size() == 1) {
1465                s.add( part.get(0) );
1466            }
1467            else {
1468                // we select a single representative
1469
Resource r = (Resource) part.remove( 0 );
1470                // remember the other equivalent values
1471
equivSets.put( r, part );
1472                s.add( r );
1473            }
1474        }
1475
1476        // now s1 contains a reduced set of nodes, in which any fully-connected sub-graph under
1477
// orderRel has been reduced to a single representative
1478

1479        // generate the short list as the maximal bound under the given partial order
1480
s = ResourceUtils.maximalLowerElements( s, orderRel, inverse );
1481
1482        // create a list of these values lower elements, plus their equivalents (if any)
1483
List s2 = new ArrayList();
1484        for (Iterator i = s.iterator(); i.hasNext(); ) {
1485            Resource r = (Resource) i.next();
1486            s2.add( r );
1487            if (equivSets.containsKey( r )) {
1488                s2.addAll( (List) equivSets.get( r ) );
1489            }
1490        }
1491
1492        // put myself back if needed
1493
if (withheld) {
1494            s2.add( this );
1495        }
1496
1497        return s2.iterator();
1498    }
1499
1500
1501    /** Remove a specified property-value pair, if it exists */
1502    protected void removePropertyValue( Property prop, String JavaDoc name, RDFNode value ) {
1503        checkProfile( prop, name );
1504
1505        StmtIterator i = getModel().listStatements( this, prop, value );
1506        if (i.hasNext()) {
1507            i.nextStatement().remove();
1508        }
1509
1510        i.close();
1511    }
1512
1513    //==============================================================================
1514
// Inner class definitions
1515
//==============================================================================
1516

1517    /** Implementation of Map1 that performs as( Class ) for a given class */
1518    protected static class AsMapper
1519        implements Map1
1520    {
1521        private Class JavaDoc m_as;
1522        public AsMapper( Class JavaDoc as ) { m_as = as; }
1523        public Object JavaDoc map1( Object JavaDoc x ) { return (x instanceof Resource) ? ((Resource) x).as( m_as ) : x; }
1524    }
1525
1526    /** Implementation of Map1 that performs as( Class ) for a given class, on the subject of a statement */
1527    protected static class SubjectAsMapper
1528        implements Map1
1529    {
1530        private Class JavaDoc m_as;
1531        public SubjectAsMapper( Class JavaDoc as ) { m_as = as; }
1532        public Object JavaDoc map1( Object JavaDoc x ) {
1533            if (x instanceof Statement) {
1534                RDFNode subj = ((Statement) x).getSubject();
1535                return (m_as == null) ? subj : subj.as( m_as );
1536            }
1537            else {
1538                return x;
1539            }
1540        }
1541    }
1542
1543    /** Implementation of Map1 that extracts the subject of a statement */
1544    protected static class SubjectMapper
1545        implements Map1
1546    {
1547        public Object JavaDoc map1( Object JavaDoc x ) {
1548            return (x instanceof Statement) ? ((Statement) x).getSubject() : x;
1549        }
1550    }
1551
1552    /** Implementation of Map1 that performs as( Class ) for a given class, on the object of a statement */
1553    protected static class ObjectAsMapper
1554        implements Map1
1555    {
1556        private Class JavaDoc m_as;
1557        public ObjectAsMapper( Class JavaDoc as ) { m_as = as; }
1558        public Object JavaDoc map1( Object JavaDoc x ) {
1559            if (x instanceof Statement) {
1560                RDFNode obj = ((Statement) x).getObject();
1561                return (m_as == null) ? obj : obj.as( m_as );
1562            }
1563            else {
1564                return x;
1565            }
1566        }
1567    }
1568
1569    /** Implementation of Map1 that performs getString on the object of a statement */
1570    protected class ObjectAsStringMapper
1571        implements Map1
1572    {
1573        public Object JavaDoc map1( Object JavaDoc x ) { return (x instanceof Statement) ? ((Statement) x).getString() : x; }
1574    }
1575
1576    /** Implementation of Map1 that returns the object of a statement */
1577    protected static class ObjectMapper
1578        implements Map1
1579    {
1580        public ObjectMapper() {}
1581        public Object JavaDoc map1( Object JavaDoc x ) { return (x instanceof Statement) ? ((Statement) x).getObject() : x; }
1582    }
1583
1584    /** Filter for matching language tags on literals */
1585    protected class LangTagFilter
1586        implements Filter
1587    {
1588        protected String JavaDoc m_lang;
1589        public LangTagFilter( String JavaDoc lang ) { m_lang = lang; }
1590        public boolean accept( Object JavaDoc x ) {
1591            if (x instanceof Literal) {
1592                return langTagMatch( m_lang, ((Literal) x).getLanguage() );
1593            }
1594            else if (x instanceof Statement) {
1595                // we assume for a statement that we're filtering on the object of the statement
1596
return accept( ((Statement) x).getObject() );
1597            }
1598            else {
1599                return false;
1600            }
1601        }
1602    }
1603
1604    /** Filter for accepting only the given value, based on .equals() */
1605    protected class SingleEqualityFilter
1606        implements Filter
1607    {
1608        private Object JavaDoc m_obj;
1609        public SingleEqualityFilter( Object JavaDoc x ) { m_obj = x; }
1610        public boolean accept( Object JavaDoc x ) {return m_obj.equals( x );}
1611    }
1612}
1613
1614
1615/*
1616    (c) Copyright 2001, 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
1617    All rights reserved.
1618
1619    Redistribution and use in source and binary forms, with or without
1620    modification, are permitted provided that the following conditions
1621    are met:
1622
1623    1. Redistributions of source code must retain the above copyright
1624       notice, this list of conditions and the following disclaimer.
1625
1626    2. Redistributions in binary form must reproduce the above copyright
1627       notice, this list of conditions and the following disclaimer in the
1628       documentation and/or other materials provided with the distribution.
1629
1630    3. The name of the author may not be used to endorse or promote products
1631       derived from this software without specific prior written permission.
1632
1633    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1634    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1635    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1636    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1637    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1638    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1639    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1640    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1641    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1642    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1643*/

1644
Popular Tags