0001: /*****************************************************************************
0002: * Source code information
0003: * -----------------------
0004: * Original author Ian Dickinson, HP Labs Bristol
0005: * Author email Ian.Dickinson@hp.com
0006: * Package Jena 2
0007: * Web http://sourceforge.net/projects/jena/
0008: * Created 27-Mar-2003
0009: * Filename $RCSfile: OntClassImpl.java,v $
0010: * Revision $Revision: 1.56 $
0011: * Release status $State: Exp $
0012: *
0013: * Last modified on $Date: 2008/01/23 12:47:00 $
0014: * by $Author: ian_dickinson $
0015: *
0016: * (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
0017: * (see footer for full conditions)
0018: *****************************************************************************/package com.hp.hpl.jena.ontology.impl;
0019:
0020: // Imports
0021: ///////////////
0022: import com.hp.hpl.jena.ontology.*;
0023: import com.hp.hpl.jena.enhanced.*;
0024: import com.hp.hpl.jena.graph.*;
0025: import com.hp.hpl.jena.graph.query.*;
0026: import com.hp.hpl.jena.rdf.model.*;
0027: import com.hp.hpl.jena.reasoner.*;
0028: import com.hp.hpl.jena.util.iterator.*;
0029: import com.hp.hpl.jena.vocabulary.*;
0030:
0031: import java.util.*;
0032:
0033: /**
0034: * <p>
0035: * Implementation of the ontology abstraction representing ontology classes.
0036: * </p>
0037: *
0038: * @author Ian Dickinson, HP Labs
0039: * (<a href="mailto:Ian.Dickinson@hp.com" >email</a>)
0040: * @version CVS $Id: OntClassImpl.java,v 1.56 2008/01/23 12:47:00 ian_dickinson Exp $
0041: */
0042: public class OntClassImpl extends OntResourceImpl implements OntClass {
0043: // Constants
0044: //////////////////////////////////
0045:
0046: /* LDP never returns properties in these namespaces */
0047: private static final String[] IGNORE_NAMESPACES = new String[] {
0048: OWL.NS, DAMLVocabulary.NAMESPACE_DAML_2001_03_URI,
0049: RDF.getURI(), RDFS.getURI(), ReasonerVocabulary.RBNamespace };
0050:
0051: // Static variables
0052: //////////////////////////////////
0053:
0054: /**
0055: * A factory for generating OntClass facets from nodes in enhanced graphs.
0056: * Note: should not be invoked directly by user code: use
0057: * {@link com.hp.hpl.jena.rdf.model.RDFNode#as as()} instead.
0058: */
0059: public static Implementation factory = new Implementation() {
0060: public EnhNode wrap(Node n, EnhGraph eg) {
0061: if (canWrap(n, eg)) {
0062: return new OntClassImpl(n, eg);
0063: } else {
0064: throw new ConversionException(
0065: "Cannot convert node "
0066: + n.toString()
0067: + " to OntClass: it does not have rdf:type owl:Class or equivalent");
0068: }
0069: }
0070:
0071: public boolean canWrap(Node node, EnhGraph eg) {
0072: // node will support being an OntClass facet if it has rdf:type owl:Class or equivalent
0073: Profile profile = (eg instanceof OntModel) ? ((OntModel) eg)
0074: .getProfile()
0075: : null;
0076: return (profile != null)
0077: && profile.isSupported(node, eg, OntClass.class);
0078: }
0079: };
0080:
0081: // Instance variables
0082: //////////////////////////////////
0083:
0084: /** Query for properties with this class as domain */
0085: protected BindingQueryPlan m_domainQuery;
0086:
0087: /** Query for properties restricted by this class */
0088: protected BindingQueryPlan m_restrictionPropQuery = null;
0089:
0090: // Constructors
0091: //////////////////////////////////
0092:
0093: /**
0094: * <p>
0095: * Construct an ontology class node represented by the given node in the given graph.
0096: * </p>
0097: *
0098: * @param n The node that represents the resource
0099: * @param g The enh graph that contains n
0100: */
0101: public OntClassImpl(Node n, EnhGraph g) {
0102: super (n, g);
0103:
0104: // pre-built queries
0105: // ?x a rdf:Property ; rdfs:domain this.
0106: Query q = new Query();
0107: q.addMatch(Query.X, getProfile().DOMAIN().asNode(), asNode());
0108:
0109: m_domainQuery = getModel().queryHandler().prepareBindings(q,
0110: new Node[] { Query.X });
0111:
0112: // this rdfs:subClassOf ?x. ?x owl:onProperty ?y.
0113: if (getProfile().ON_PROPERTY() != null) {
0114: q = new Query();
0115: q.addMatch(asNode(), getProfile().SUB_CLASS_OF().asNode(),
0116: Query.X);
0117: q.addMatch(Query.X, getProfile().ON_PROPERTY().asNode(),
0118: Query.Y);
0119:
0120: m_restrictionPropQuery = getModel().queryHandler()
0121: .prepareBindings(q, new Node[] { Query.Y });
0122: }
0123: }
0124:
0125: // External signature methods
0126: //////////////////////////////////
0127:
0128: // subClassOf
0129:
0130: /**
0131: * <p>Assert that this class is sub-class of the given class. Any existing
0132: * statements for <code>subClassOf</code> will be removed.</p>
0133: * @param cls The class that this class is a sub-class of
0134: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0135: */
0136: public void setSuperClass(Resource cls) {
0137: setPropertyValue(getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF",
0138: cls);
0139: }
0140:
0141: /**
0142: * <p>Add a super-class of this class.</p>
0143: * @param cls A class that is a super-class of this class.
0144: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0145: */
0146: public void addSuperClass(Resource cls) {
0147: addPropertyValue(getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF",
0148: cls);
0149: }
0150:
0151: /**
0152: * <p>Answer a class that is the super-class of this class. If there is
0153: * more than one such class, an arbitrary selection is made.</p>
0154: * @return A super-class of this class
0155: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0156: */
0157: public OntClass getSuperClass() {
0158: return (OntClass) objectAs(getProfile().SUB_CLASS_OF(),
0159: "SUB_CLASS_OF", OntClass.class);
0160: }
0161:
0162: /**
0163: * <p>Answer an iterator over all of the classes that are declared to be super-classes of
0164: * this class. Each element of the iterator will be an {@link OntClass}.</p>
0165: * @return An iterator over the super-classes of this class.
0166: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0167: */
0168: public ExtendedIterator listSuperClasses() {
0169: return listSuperClasses(false);
0170: }
0171:
0172: /**
0173: * <p>Answer an iterator over all of the classes that are declared to be super-classes of
0174: * this class. Each element of the iterator will be an {@link OntClass}.
0175: * See {@link #listSubClasses( boolean )} for a full explanation of the <em>direct</em>
0176: * parameter.
0177: * </p>
0178: *
0179: * @param direct If true, only answer the direcly adjacent classes in the
0180: * super-class relation: i.e. eliminate any class for which there is a longer route
0181: * to reach that child under the super-class relation.
0182: * @return an iterator over the resources representing this class's sub-classes.
0183: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0184: */
0185: public ExtendedIterator listSuperClasses(boolean direct) {
0186: return UniqueExtendedIterator.create(listDirectPropertyValues(
0187: getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF",
0188: OntClass.class, getProfile().SUB_CLASS_OF(), direct,
0189: false).filterDrop(new SingleEqualityFilter(this )));
0190: }
0191:
0192: /**
0193: * <p>Answer true if the given class is a super-class of this class.</p>
0194: * @param cls A class to test.
0195: * @return True if the given class is a super-class of this class.
0196: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0197: */
0198: public boolean hasSuperClass(Resource cls) {
0199: return hasSuperClass(cls, false);
0200: }
0201:
0202: /**
0203: * <p>Answer true if this class has any super-class in the model. Note that
0204: * when using a reasoner, all OWL classes have owl:Thing as a super-class.</p>
0205: * @return True if this class has any known super-class.
0206: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0207: */
0208: public boolean hasSuperClass() {
0209: return getSuperClass() != null;
0210: }
0211:
0212: /**
0213: * <p>Answer true if the given class is a super-class of this class.
0214: * See {@link #listSubClasses( boolean )} for a full explanation of the <em>direct</em>
0215: * parameter.
0216: * </p>
0217: * @param cls A class to test.
0218: * @param direct If true, only search the classes that are directly adjacent to this
0219: * class in the class hierarchy.
0220: * @return True if the given class is a super-class of this class.
0221: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0222: */
0223: public boolean hasSuperClass(Resource cls, boolean direct) {
0224: if (!direct) {
0225: // don't need any special case, we just get the property
0226: return hasPropertyValue(getProfile().SUB_CLASS_OF(),
0227: "SUB_CLASS_OF", cls);
0228: } else {
0229: // we want the direct, not general relationship
0230: // first try to find an inf graph that can do the work for us
0231: InfGraph ig = null;
0232: if (getGraph() instanceof InfGraph) {
0233: ig = (InfGraph) getGraph();
0234: } else if (getGraph() instanceof OntModel) {
0235: OntModel m = (OntModel) getGraph();
0236: if (m.getGraph() instanceof InfGraph) {
0237: ig = (InfGraph) m.getGraph();
0238: }
0239: }
0240:
0241: if (ig != null
0242: && ig.getReasoner().supportsProperty(
0243: ReasonerVocabulary.directSubClassOf)) {
0244: // we can look this up directly
0245: return hasPropertyValue(
0246: ReasonerVocabulary.directSubClassOf,
0247: "direct sub-class", cls);
0248: } else {
0249: // otherwise, not an inf-graph or the given inf-graph does not support direct directly (:-)
0250: return hasSuperClassDirect(cls);
0251: }
0252: }
0253: }
0254:
0255: /**
0256: * <p>Remove the given class from the super-classes of this class. If this statement
0257: * is not true of the current model, nothing happens.</p>
0258: * @param cls A class to be removed from the super-classes of this class
0259: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} class is not supported in the current language profile.
0260: */
0261: public void removeSuperClass(Resource cls) {
0262: removePropertyValue(getProfile().SUB_CLASS_OF(),
0263: "SUB_CLASS_OF", cls);
0264: }
0265:
0266: /**
0267: * <p>Assert that this class is super-class of the given class. Any existing
0268: * statements for <code>subClassOf</code> on <code>prop</code> will be removed.</p>
0269: * @param cls The class that is a sub-class of this class
0270: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0271: */
0272: public void setSubClass(Resource cls) {
0273: // first we have to remove all of the inverse sub-class links
0274: checkProfile(getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF");
0275: for (StmtIterator i = getModel().listStatements(null,
0276: getProfile().SUB_CLASS_OF(), this ); i.hasNext();) {
0277: i.removeNext();
0278: }
0279:
0280: ((OntClass) cls.as(OntClass.class)).addSuperClass(this );
0281: }
0282:
0283: /**
0284: * <p>Add a sub-class of this class.</p>
0285: * @param cls A class that is a sub-class of this class.
0286: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0287: */
0288: public void addSubClass(Resource cls) {
0289: ((OntClass) cls.as(OntClass.class)).addSuperClass(this );
0290: }
0291:
0292: /**
0293: * <p>Answer a class that is the sub-class of this class. If there is
0294: * more than one such class, an arbitrary selection is made. If
0295: * there is no such class, return null.</p>
0296: * @return A sub-class of this class or null
0297: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()}
0298: * property is not supported in the current language profile.
0299: */
0300: public OntClass getSubClass() {
0301: checkProfile(getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF");
0302: StmtIterator i = getModel().listStatements(null,
0303: getProfile().SUB_CLASS_OF(), this );
0304: try {
0305: if (i.hasNext()) {
0306: return (OntClass) i.nextStatement().getSubject().as(
0307: OntClass.class);
0308: } else {
0309: return null;
0310: }
0311: } finally {
0312: i.close();
0313: }
0314: }
0315:
0316: /**
0317: * <p>Answer an iterator over all of the classes that are declared to be sub-classes of
0318: * this class. Each element of the iterator will be an {@link OntClass}.</p>
0319: * @return An iterator over the sub-classes of this class.
0320: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0321: */
0322: public ExtendedIterator listSubClasses() {
0323: return listSubClasses(false);
0324: }
0325:
0326: /**
0327: * <p>
0328: * Answer an iterator over the classes that are declared to be sub-classes of
0329: * this class. Each element of the iterator will be an {@link OntClass}. The
0330: * distinguishing extra parameter for this method is the flag <code>direct</code>
0331: * that allows some selectivity over the classes that appear in the iterator.
0332: * Consider the following scenario:
0333: * <code><pre>
0334: * :B rdfs:subClassOf :A.
0335: * :C rdfs:subClassOf :A.
0336: * :D rdfs:subClassof :C.
0337: * </pre></code>
0338: * (so A has two sub-classes, B and C, and C has sub-class D). In a raw model, with
0339: * no inference support, listing the sub-classes of A will answer B and C. In an
0340: * inferencing model, <code>rdfs:subClassOf</code> is known to be transitive, so
0341: * the sub-classes iterator will include D. The <code>direct</code> sub-classes
0342: * are those members of the closure of the subClassOf relation, restricted to classes that
0343: * cannot be reached by a longer route, i.e. the ones that are <em>directly</em> adjacent
0344: * to the given root. Thus, the direct sub-classes of A are B and C only, and not D -
0345: * even in an inferencing graph. Note that this is not the same as the entailments
0346: * from the raw graph. Suppose we add to this example:
0347: * <code><pre>
0348: * :D rdfs:subClassof :A.
0349: * </pre></code>
0350: * Now, in the raw graph, A has sub-class C. But the direct sub-classes of A remain
0351: * B and C, since there is a longer path A-C-D that means that D is not a direct sub-class
0352: * of A. The assertion in the raw graph that A has sub-class D is essentially redundant,
0353: * since this can be inferred from the closure of the graph.
0354: * </p>
0355: * <p>
0356: * <strong>Note:</strong> This is is a change from the behaviour of Jena 1, which took a
0357: * parameter <code>closed</code> to compute the closure over transitivity and equivalence
0358: * of sub-classes. The closure capability in Jena2 is determined by the inference engine
0359: * that is wrapped with the ontology model. The direct parameter is provided to allow,
0360: * for exmaple, a level-by-level traversal of the class hierarchy, starting at some given
0361: * root.
0362: * </p>
0363: *
0364: * @param direct If true, only answer the direcly adjacent classes in the
0365: * sub-class relation: i.e. eliminate any class for which there is a longer route
0366: * to reach that child under the sub-class relation.
0367: * @return an iterator over the resources representing this class's sub-classes
0368: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0369: */
0370: public ExtendedIterator listSubClasses(boolean direct) {
0371: return UniqueExtendedIterator.create(listDirectPropertyValues(
0372: getProfile().SUB_CLASS_OF(), "SUB_CLASS_OF",
0373: OntClass.class, getProfile().SUB_CLASS_OF(), direct,
0374: true).filterDrop(new SingleEqualityFilter(this )));
0375: }
0376:
0377: /**
0378: * <p>Answer true if the given class is a sub-class of this class.</p>
0379: * @param cls A class to test.
0380: * @return True if the given class is a sub-class of this class.
0381: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0382: */
0383: public boolean hasSubClass(Resource cls) {
0384: return hasSubClass(cls, false);
0385: }
0386:
0387: /**
0388: * <p>Answer true if this class has any sub-class in the model. Note that
0389: * when using a reasoner, all OWL classes have owl:Nothing as a sub-class.</p>
0390: * @return True if this class has any known sub-class.
0391: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0392: */
0393: public boolean hasSubClass() {
0394: return getSubClass() != null;
0395: }
0396:
0397: /**
0398: * <p>Answer true if the given class is a sub-class of this class.
0399: * See {@link #listSubClasses( boolean )} for a full explanation of the <em>direct</em>
0400: * parameter.
0401: * </p>
0402: * @param cls A class to test.
0403: * @param direct If true, only search the classes that are directly adjacent to this
0404: * class in the class hierarchy.
0405: * @return True if the given class is a sub-class of this class.
0406: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} property is not supported in the current language profile.
0407: */
0408: public boolean hasSubClass(Resource cls, boolean direct) {
0409: if (getModel() instanceof OntModel
0410: && (cls.getModel() == null || !(cls.getModel() instanceof OntModel))) {
0411: // could be outside an ontmodel if a constant
0412: cls = (Resource) cls.inModel(getModel());
0413: }
0414: return ((OntClass) cls.as(OntClass.class)).hasSuperClass(this ,
0415: direct);
0416: }
0417:
0418: /**
0419: * <p>Remove the given class from the sub-classes of this class. If this statement
0420: * is not true of the current model, nothing happens.</p>
0421: * @param cls A class to be removed from the sub-classes of this class
0422: * @exception OntProfileException If the {@link Profile#SUB_CLASS_OF()} class is not supported in the current language profile.
0423: */
0424: public void removeSubClass(Resource cls) {
0425: ((OntClass) cls.as(OntClass.class)).removeSuperClass(this );
0426: }
0427:
0428: // equivalentClass
0429:
0430: /**
0431: * <p>Assert that the given class is equivalent to this class. Any existing
0432: * statements for <code>equivalentClass</code> will be removed.</p>
0433: * @param cls The class that this class is a equivalent to.
0434: * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()} property is not supported in the current language profile.
0435: */
0436: public void setEquivalentClass(Resource cls) {
0437: setPropertyValue(getProfile().EQUIVALENT_CLASS(),
0438: "EQUIVALENT_CLASS", cls);
0439: }
0440:
0441: /**
0442: * <p>Add a class that is equivalent to this class.</p>
0443: * @param cls A class that is equivalent to this class.
0444: * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()} property is not supported in the current language profile.
0445: */
0446: public void addEquivalentClass(Resource cls) {
0447: addPropertyValue(getProfile().EQUIVALENT_CLASS(),
0448: "EQUIVALENT_CLASS", cls);
0449: }
0450:
0451: /**
0452: * <p>Answer a class that is equivalent to this class. If there is
0453: * more than one such class, an arbitrary selection is made.</p>
0454: * @return A class equivalent to this class
0455: * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()} property is not supported in the current language profile.
0456: */
0457: public OntClass getEquivalentClass() {
0458: return (OntClass) objectAs(getProfile().EQUIVALENT_CLASS(),
0459: "EQUIVALENT_CLASS", OntClass.class);
0460: }
0461:
0462: /**
0463: * <p>Answer an iterator over all of the classes that are declared to be equivalent classes to
0464: * this class. Each element of the iterator will be an {@link OntClass}.</p>
0465: * @return An iterator over the classes equivalent to this class.
0466: * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()} property is not supported in the current language profile.
0467: */
0468: public ExtendedIterator listEquivalentClasses() {
0469: return UniqueExtendedIterator
0470: .create(listAs(getProfile().EQUIVALENT_CLASS(),
0471: "EQUIVALENT_CLASS", OntClass.class));
0472: }
0473:
0474: /**
0475: * <p>Answer true if the given class is equivalent to this class.</p>
0476: * @param cls A class to test for
0477: * @return True if the given property is equivalent to this class.
0478: * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()} property is not supported in the current language profile.
0479: */
0480: public boolean hasEquivalentClass(Resource cls) {
0481: return hasPropertyValue(getProfile().EQUIVALENT_CLASS(),
0482: "EQUIVALENT_CLASS", cls);
0483: }
0484:
0485: /**
0486: * <p>Remove the statement that this class and the given class are
0487: * equivalent. If this statement
0488: * is not true of the current model, nothing happens.</p>
0489: * @param cls A class that may be declared to be equivalent to this class, and which is no longer equivalent
0490: * @exception OntProfileException If the {@link Profile#EQUIVALENT_CLASS()()} property is not supported in the current language profile.
0491: */
0492: public void removeEquivalentClass(Resource cls) {
0493: removePropertyValue(getProfile().EQUIVALENT_CLASS(),
0494: "EQUIVALENT_CLASS", cls);
0495: }
0496:
0497: // disjointWith
0498:
0499: /**
0500: * <p>Assert that this class is disjoint with the given class. Any existing
0501: * statements for <code>disjointWith</code> will be removed.</p>
0502: * @param cls The property that this class is disjoint with.
0503: * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()} property is not supported in the current language profile.
0504: */
0505: public void setDisjointWith(Resource cls) {
0506: setPropertyValue(getProfile().DISJOINT_WITH(), "DISJOINT_WITH",
0507: cls);
0508: }
0509:
0510: /**
0511: * <p>Add a class that this class is disjoint with.</p>
0512: * @param cls A class that has no instances in common with this class.
0513: * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()} property is not supported in the current language profile.
0514: */
0515: public void addDisjointWith(Resource cls) {
0516: addPropertyValue(getProfile().DISJOINT_WITH(), "DISJOINT_WITH",
0517: cls);
0518: }
0519:
0520: /**
0521: * <p>Answer a class with which this class is disjoint. If there is
0522: * more than one such class, an arbitrary selection is made.</p>
0523: * @return A class disjoint with this class
0524: * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()} property is not supported in the current language profile.
0525: */
0526: public OntClass getDisjointWith() {
0527: return (OntClass) objectAs(getProfile().DISJOINT_WITH(),
0528: "DISJOINT_WITH", OntClass.class);
0529: }
0530:
0531: /**
0532: * <p>Answer an iterator over all of the classes that this class is declared to be disjoint with.
0533: * Each element of the iterator will be an {@link OntClass}.</p>
0534: * @return An iterator over the classes disjoint with this class.
0535: * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()} property is not supported in the current language profile.
0536: */
0537: public ExtendedIterator listDisjointWith() {
0538: return UniqueExtendedIterator.create(listAs(getProfile()
0539: .DISJOINT_WITH(), "DISJOINT_WITH", OntClass.class));
0540: }
0541:
0542: /**
0543: * <p>Answer true if this class is disjoint with the given class.</p>
0544: * @param cls A class to test
0545: * @return True if the this class is disjoint with the the given class.
0546: * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()} property is not supported in the current language profile.
0547: */
0548: public boolean isDisjointWith(Resource cls) {
0549: return hasPropertyValue(getProfile().DISJOINT_WITH(),
0550: "DISJOINT_WITH", cls);
0551: }
0552:
0553: /**
0554: * <p>Remove the statement that this class and the given class are
0555: * disjoint. If this statement
0556: * is not true of the current model, nothing happens.</p>
0557: * @param cls A class that may be declared to be disjoint with this class, and which is no longer disjoint
0558: * @exception OntProfileException If the {@link Profile#DISJOINT_WITH()()()} property is not supported in the current language profile.
0559: */
0560: public void removeDisjointWith(Resource cls) {
0561: removePropertyValue(getProfile().DISJOINT_WITH(),
0562: "DISJOINT_WITH", cls);
0563: }
0564:
0565: // other utility methods
0566:
0567: /**
0568: * <p>Answer an iteration of the properties associated with a frame-like
0569: * view of this class. Note that many cases of determining whether a
0570: * property is associated with a class depends on RDFS or OWL reasoning.
0571: * This method may therefore return complete results only in models that
0572: * have an attached reasoner.
0573: * See the
0574: * <a href="../../../../../../how-to/rdf-frames.html">RDF frames how-to</a>
0575: * for full details.<p>
0576: * @return An iteration of the properties that are associated with this class
0577: * by their domain.
0578: */
0579: public ExtendedIterator listDeclaredProperties() {
0580: return listDeclaredProperties(false);
0581: }
0582:
0583: /**
0584: * <p>Answer an iteration of the properties associated with a frame-like
0585: * view of this class. Note that many cases of determining whether a
0586: * property is associated with a class depends on RDFS or OWL reasoning.
0587: * This method may therefore return complete results only in models that
0588: * have an attached reasoner. See the
0589: * <a href="../../../../../../how-to/rdf-frames.html">RDF frames how-to</a>
0590: * for full details.<p>
0591: * @param direct If true, restrict the properties returned to those directly
0592: * associated with this class.
0593: * @return An iteration of the properties that are associated with this class
0594: * by their domain.
0595: */
0596: public ExtendedIterator listDeclaredProperties(boolean direct) {
0597: // first collect the candidate properties
0598: Set candSet = new HashSet();
0599:
0600: // if the attached model does inference, it will potentially find more of these
0601: // than a non-inference model
0602: for (Iterator i = listAllProperties(); i.hasNext();) {
0603: candSet.add(((Statement) i.next()).getSubject().as(
0604: Property.class));
0605: }
0606:
0607: // now we iterate over the candidates and check that they match all domain constraints
0608: List cands = new ArrayList();
0609: cands.addAll(candSet);
0610: for (int j = cands.size() - 1; j >= 0; j--) {
0611: Property cand = (Property) cands.get(j);
0612: if (!hasDeclaredProperty(cand, direct)) {
0613: cands.remove(j);
0614: }
0615: }
0616:
0617: // return the results, using the ont property facet
0618: return WrappedIterator.create(cands.iterator()).mapWith(
0619: new AsMapper(OntProperty.class));
0620: }
0621:
0622: /**
0623: * <p>Answer true if the given property is one of the declared properties
0624: * of this class. For details, see {@link #listDeclaredProperties(boolean)}.</p>
0625: * @param p A property to test
0626: * @param direct If true, only direct associations between classes and properties
0627: * are considered
0628: * @return True if <code>p</code> is one of the declared properties of
0629: * this class
0630: */
0631: public boolean hasDeclaredProperty(Property p, boolean direct) {
0632: return testDomain(p, direct);
0633: }
0634:
0635: /**
0636: * <p>Answer an iterator over the individuals in the model that have this
0637: * class among their types.<p>
0638: *
0639: * @return An iterator over those instances that have this class as one of
0640: * the classes to which they belong
0641: */
0642: public ExtendedIterator listInstances() {
0643: return listInstances(false);
0644: }
0645:
0646: /**
0647: * <p>Answer an iterator over the individuals in the model that have this
0648: * class among their types, optionally excluding sub-classes of this class.<p>
0649: *
0650: * @param direct If true, only direct instances are counted (i.e. not instances
0651: * of sub-classes of this class)
0652: * @return An iterator over those instances that have this class as one of
0653: * the classes to which they belong
0654: */
0655: public ExtendedIterator listInstances(final boolean direct) {
0656: return UniqueExtendedIterator.create(getModel().listStatements(
0657: null, RDF.type, this ).mapWith(
0658: new SubjectAsMapper(Individual.class)).filterKeep(
0659: new Filter() {
0660: public boolean accept(Object o) {
0661: // if direct, ignore the sub-class typed resources
0662: return ((Individual) o).hasRDFType(
0663: OntClassImpl.this , direct);
0664: }
0665: }));
0666: }
0667:
0668: /**
0669: * <p>Answer a new individual that has this class as its <code>rdf:type</code></p>
0670: * @return A new anonymous individual that is an instance of this class
0671: */
0672: public Individual createIndividual() {
0673: return ((OntModel) getModel()).createIndividual(this );
0674: }
0675:
0676: /**
0677: * <p>Answer a new individual that has this class as its <code>rdf:type</code></p>
0678: * @param uri The URI of the new individual
0679: * @return A new named individual that is an instance of this class
0680: */
0681: public Individual createIndividual(String uri) {
0682: return ((OntModel) getModel()).createIndividual(uri, this );
0683: }
0684:
0685: /**
0686: * <p>Remove the given individual from the set of instances that are members of
0687: * this class. This is effectively equivalent to the {@link Individual#removeOntClass} method,
0688: * but invoked via the class resource rather than via the individual resource.</p>
0689: * @param individual A resource denoting an individual that is no longer to be a member
0690: * of this class
0691: */
0692: public void dropIndividual(Resource individual) {
0693: getModel().remove(individual, RDF.type, this );
0694: }
0695:
0696: /**
0697: * <p>Answer true if this class is one of the roots of the class hierarchy.
0698: * This will be true if either (i) this class has <code>owl:Thing</code>
0699: * (or <code>daml:Thing</code>) as a direct super-class, or (ii) it has
0700: * no declared super-classes (including anonymous class expressions).</p>
0701: * @return True if this class is the root of the class hierarchy in the
0702: * model it is attached to
0703: */
0704: public boolean isHierarchyRoot() {
0705: // sanity check - :Nothing is never a root class
0706: if (equals(getProfile().NOTHING())) {
0707: return false;
0708: }
0709:
0710: // the only super-classes of a root class are the various aliases
0711: // of Top, or itself
0712:
0713: /**
0714: Note: moved the initialisation of i outside the try-catch, otherwise an
0715: exception in listSuperClasses [eg a broken Graph implementation] will
0716: avoid i's initialisation but still run i.close, generating a mysterious
0717: NullPointerException. Signed, Mr Burnt Spines.
0718: */
0719: ExtendedIterator i = listSuperClasses(true);
0720: try {
0721:
0722: while (i.hasNext()) {
0723: Resource sup = (Resource) i.next();
0724: if (!(sup.equals(getProfile().THING())
0725: || sup.equals(RDFS.Resource) || sup
0726: .equals(this ))) {
0727: // a super that indicates this is not a root class
0728: return false;
0729: }
0730: }
0731: } finally {
0732: i.close();
0733: }
0734:
0735: return true;
0736: }
0737:
0738: // access to facets
0739: /**
0740: * <p>Answer a view of this class as an enumerated class</p>
0741: * @return This class, but viewed as an EnumeratedClass node
0742: * @exception ConversionException if the class cannot be converted to an enumerated class
0743: * given the lanuage profile and the current state of the underlying model.
0744: */
0745: public EnumeratedClass asEnumeratedClass() {
0746: return (EnumeratedClass) as(EnumeratedClass.class);
0747: }
0748:
0749: /**
0750: * <p>Answer a view of this class as a union class</p>
0751: * @return This class, but viewed as a UnionClass node
0752: * @exception ConversionException if the class cannot be converted to a union class
0753: * given the lanuage profile and the current state of the underlying model.
0754: */
0755: public UnionClass asUnionClass() {
0756: return (UnionClass) as(UnionClass.class);
0757: }
0758:
0759: /**
0760: * <p>Answer a view of this class as an intersection class</p>
0761: * @return This class, but viewed as an IntersectionClass node
0762: * @exception ConversionException if the class cannot be converted to an intersection class
0763: * given the lanuage profile and the current state of the underlying model.
0764: */
0765: public IntersectionClass asIntersectionClass() {
0766: return (IntersectionClass) as(IntersectionClass.class);
0767: }
0768:
0769: /**
0770: * <p>Answer a view of this class as a complement class</p>
0771: * @return This class, but viewed as a ComplementClass node
0772: * @exception ConversionException if the class cannot be converted to a complement class
0773: * given the lanuage profile and the current state of the underlying model.
0774: */
0775: public ComplementClass asComplementClass() {
0776: return (ComplementClass) as(ComplementClass.class);
0777: }
0778:
0779: /**
0780: * <p>Answer a view of this class as a restriction class expression</p>
0781: * @return This class, but viewed as a Restriction node
0782: * @exception ConversionException if the class cannot be converted to a restriction
0783: * given the lanuage profile and the current state of the underlying model.
0784: */
0785: public Restriction asRestriction() {
0786: return (Restriction) as(Restriction.class);
0787: }
0788:
0789: // sub-type testing
0790:
0791: /**
0792: * <p>Answer true if this class is an enumerated class expression</p>
0793: * @return True if this is an enumerated class expression
0794: */
0795: public boolean isEnumeratedClass() {
0796: checkProfile(getProfile().ONE_OF(), "ONE_OF");
0797: return hasProperty(getProfile().ONE_OF());
0798: }
0799:
0800: /**
0801: * <p>Answer true if this class is a union class expression</p>
0802: * @return True if this is a union class expression
0803: */
0804: public boolean isUnionClass() {
0805: checkProfile(getProfile().UNION_OF(), "UNION_OF");
0806: return hasProperty(getProfile().UNION_OF());
0807: }
0808:
0809: /**
0810: * <p>Answer true if this class is an intersection class expression</p>
0811: * @return True if this is an intersection class expression
0812: */
0813: public boolean isIntersectionClass() {
0814: checkProfile(getProfile().INTERSECTION_OF(), "INTERSECTION_OF");
0815: return hasProperty(getProfile().INTERSECTION_OF());
0816: }
0817:
0818: /**
0819: * <p>Answer true if this class is a complement class expression</p>
0820: * @return True if this is a complement class expression
0821: */
0822: public boolean isComplementClass() {
0823: checkProfile(getProfile().COMPLEMENT_OF(), "COMPLEMENT_OF");
0824: return hasProperty(getProfile().COMPLEMENT_OF());
0825: }
0826:
0827: /**
0828: * <p>Answer true if this class is a property restriction</p>
0829: * @return True if this is a restriction
0830: */
0831: public boolean isRestriction() {
0832: checkProfile(getProfile().RESTRICTION(), "RESTRICTION");
0833: return hasProperty(getProfile().ON_PROPERTY())
0834: || hasProperty(RDF.type, getProfile().RESTRICTION());
0835: }
0836:
0837: // conversion operations
0838:
0839: /**
0840: * <p>Answer a view of this class as an enumeration of the given individuals.</p>
0841: * @param individuals A list of the individuals that will comprise the permitted values of this
0842: * class converted to an enumeration
0843: * @return This ontology class, converted to an enumeration of the given individuals
0844: */
0845: public EnumeratedClass convertToEnumeratedClass(RDFList individuals) {
0846: setPropertyValue(getProfile().ONE_OF(), "ONE_OF", individuals);
0847: return (EnumeratedClass) as(EnumeratedClass.class);
0848: }
0849:
0850: /**
0851: * <p>Answer a view of this class as an intersection of the given classes.</p>
0852: * @param classes A list of the classes that will comprise the operands of the intersection
0853: * @return This ontology class, converted to an intersection of the given classes
0854: */
0855: public IntersectionClass convertToIntersectionClass(RDFList classes) {
0856: setPropertyValue(getProfile().INTERSECTION_OF(),
0857: "INTERSECTION_OF", classes);
0858: return (IntersectionClass) as(IntersectionClass.class);
0859: }
0860:
0861: /**
0862: * <p>Answer a view of this class as a union of the given classes.</p>
0863: * @param classes A list of the classes that will comprise the operands of the union
0864: * @return This ontology class, converted to an union of the given classes
0865: */
0866: public UnionClass convertToUnionClass(RDFList classes) {
0867: setPropertyValue(getProfile().UNION_OF(), "UNION_OF", classes);
0868: return (UnionClass) as(UnionClass.class);
0869: }
0870:
0871: /**
0872: * <p>Answer a view of this class as an complement of the given class.</p>
0873: * @param cls An ontology classs that will be operand of the complement
0874: * @return This ontology class, converted to an complement of the given class
0875: */
0876: public ComplementClass convertToComplementClass(Resource cls) {
0877: setPropertyValue(getProfile().COMPLEMENT_OF(), "COMPLEMENT_OF",
0878: cls);
0879: return (ComplementClass) as(ComplementClass.class);
0880: }
0881:
0882: /**
0883: * <p>Answer a view of this class as an resriction on the given property.</p>
0884: * @param prop A property this is the subject of a property restriction class expression
0885: * @return This ontology class, converted to a restriction on the given property
0886: */
0887: public Restriction convertToRestriction(Property prop) {
0888: if (!hasRDFType(getProfile().RESTRICTION(), "RESTRICTION",
0889: false)) {
0890: setRDFType(getProfile().RESTRICTION());
0891: }
0892: setPropertyValue(getProfile().ON_PROPERTY(), "ON_PROPERTY",
0893: prop);
0894: return (Restriction) as(Restriction.class);
0895: }
0896:
0897: // Internal implementation methods
0898: //////////////////////////////////
0899:
0900: /**
0901: * <p>Answer true if this class has the given class as a direct super-class, without using
0902: * extra help from the reasoner.</p>
0903: * @param cls The class to test
0904: * @return True if the cls is a direct super-class of this class
0905: */
0906: protected boolean hasSuperClassDirect(Resource cls) {
0907: // we manually compute the maximal lower elements - this could be expensive in general
0908: //return ResourceUtils.maximalLowerElements( listSuperClasses(), getProfile().SUB_CLASS_OF(), false ).contains( cls );
0909:
0910: ExtendedIterator i = listDirectPropertyValues(getProfile()
0911: .SUB_CLASS_OF(), "subClassOf", OntClass.class,
0912: getProfile().SUB_CLASS_OF(), true, false);
0913: try {
0914: while (i.hasNext()) {
0915: if (cls.equals(i.next())) {
0916: return true;
0917: }
0918: }
0919: } finally {
0920: i.close();
0921: }
0922:
0923: return false;
0924: }
0925:
0926: /**
0927: * <p>Answer true if this class lies with the domain of p<p>
0928: * @param p
0929: * @param direct If true, only consider direct associations with domain
0930: * @return True if this class in the domain of property <code>p</code>
0931: */
0932: protected boolean testDomain(Property p, boolean direct) {
0933: // we ignore any property in the DAML, OWL, etc namespace
0934: String namespace = p.getNameSpace();
0935: for (int i = 0; i < IGNORE_NAMESPACES.length; i++) {
0936: if (namespace.equals(IGNORE_NAMESPACES[i])) {
0937: return false;
0938: }
0939: }
0940:
0941: // check for global props, that have no specific domain constraint
0942: boolean isGlobal = true;
0943:
0944: // flag for detecting the direct case
0945: boolean seenDirect = false;
0946:
0947: for (StmtIterator i = getModel().listStatements(p,
0948: getProfile().DOMAIN(), (RDFNode) null); i.hasNext();) {
0949: Resource domain = i.nextStatement().getResource();
0950:
0951: // there are some well-known values we ignore
0952: if (!(domain.equals(getProfile().THING()) || domain
0953: .equals(RDFS.Resource))) {
0954: // not a generic domain
0955: isGlobal = false;
0956:
0957: if (domain.equals(this )) {
0958: // if this class is actually in the domain (as opposed to one of this class's
0959: // super-classes), then we've detected the direct property case
0960: seenDirect = true;
0961: } else if (!canProveSuperClass(domain)) {
0962: // there is a class in the domain of p that is not a super-class of this class
0963: return false;
0964: }
0965: }
0966: }
0967:
0968: if (direct) {
0969: // if we're looking for direct props, we must either have seen the direct case
0970: // or it's a global prop and this is a root class
0971: return seenDirect || (isGlobal && isHierarchyRoot());
0972: } else {
0973: // not direct, we must either found a global or a super-class prop
0974: // otherwise the 'return false' above would have kicked in
0975: return true;
0976: }
0977: }
0978:
0979: /**
0980: * <p>Answer an iterator over all of the properties in this model
0981: * @return An iterator over {@link OntProperty}
0982: */
0983: protected ExtendedIterator listAllProperties() {
0984: OntModel mOnt = (OntModel) getModel();
0985: Profile prof = mOnt.getProfile();
0986:
0987: ExtendedIterator pi = mOnt.listStatements(null, RDF.type,
0988: getProfile().PROPERTY());
0989:
0990: // check reasoner capabilities - major performance improvement for inf models
0991: if (mOnt.getReasoner() != null) {
0992: Model caps = mOnt.getReasoner().getReasonerCapabilities();
0993: if (caps.contains(null, ReasonerVocabulary.supportsP,
0994: OWL.ObjectProperty)
0995: || caps.contains(null,
0996: ReasonerVocabulary.supportsP,
0997: DAML_OIL.ObjectProperty)) {
0998: // we conclude that the reasoner can do the necessary work to infer that
0999: // all owl:ObjectProperty, owl:DatatypeProperty, etc, are rdf:Property resources
1000: return pi;
1001: }
1002: }
1003:
1004: // otherwise, we manually check the other property types
1005: if (prof.OBJECT_PROPERTY() != null) {
1006: pi = pi.andThen(mOnt.listStatements(null, RDF.type, prof
1007: .OBJECT_PROPERTY()));
1008: }
1009: if (prof.DATATYPE_PROPERTY() != null) {
1010: pi = pi.andThen(mOnt.listStatements(null, RDF.type, prof
1011: .DATATYPE_PROPERTY()));
1012: }
1013: if (prof.FUNCTIONAL_PROPERTY() != null) {
1014: pi = pi.andThen(mOnt.listStatements(null, RDF.type, prof
1015: .FUNCTIONAL_PROPERTY()));
1016: }
1017: if (prof.INVERSE_FUNCTIONAL_PROPERTY() != null) {
1018: pi = pi.andThen(mOnt.listStatements(null, RDF.type, prof
1019: .INVERSE_FUNCTIONAL_PROPERTY()));
1020: }
1021: if (prof.SYMMETRIC_PROPERTY() != null) {
1022: pi = pi.andThen(mOnt.listStatements(null, RDF.type, prof
1023: .SYMMETRIC_PROPERTY()));
1024: }
1025: if (prof.TRANSITIVE_PROPERTY() != null) {
1026: pi = pi.andThen(mOnt.listStatements(null, RDF.type, prof
1027: .TRANSITIVE_PROPERTY()));
1028: }
1029: if (prof.ANNOTATION_PROPERTY() != null) {
1030: pi = pi.andThen(mOnt.listStatements(null, RDF.type, prof
1031: .ANNOTATION_PROPERTY()));
1032: }
1033:
1034: return pi;
1035: }
1036:
1037: /**
1038: * <p>Answer true if we can demonstrate that this class has the given super-class.
1039: * If this model has a reasoner, this is equivalent to asking if the sub-class
1040: * relation holds. Otherwise, we simulate basic reasoning by searching upwards
1041: * through the class hierarchy.</p>
1042: * @param sup A super-class to test for
1043: * @return True if we can show that sup is a super-class of thsi class
1044: */
1045: protected boolean canProveSuperClass(Resource sup) {
1046: OntModel om = (OntModel) getModel();
1047: if (om.getReasoner() != null) {
1048: if (om.getReasoner().getReasonerCapabilities()
1049: .contains(null, ReasonerVocabulary.supportsP,
1050: RDFS.subClassOf)) {
1051: // this reasoner does transitive closure on sub-classes, so we just ask
1052: return hasSuperClass(sup);
1053: }
1054: }
1055:
1056: // otherwise, we have to search upwards through the class hierarchy
1057: Set seen = new HashSet();
1058: List queue = new ArrayList();
1059: queue.add(this );
1060:
1061: while (!queue.isEmpty()) {
1062: OntClass c = (OntClass) queue.remove(0);
1063: if (!seen.contains(c)) {
1064: seen.add(c);
1065:
1066: if (c.equals(sup)) {
1067: // found the super class
1068: return true;
1069: } else {
1070: // queue the supers
1071: for (Iterator i = c.listSuperClasses(); i.hasNext();) {
1072: queue.add(i.next());
1073: }
1074: }
1075: }
1076: }
1077:
1078: // to get here, we didn't find the class we were looking for
1079: return false;
1080: }
1081:
1082: //==============================================================================
1083: // Inner class definitions
1084: //==============================================================================
1085:
1086: }
1087:
1088: /*
1089: (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
1090: All rights reserved.
1091:
1092: Redistribution and use in source and binary forms, with or without
1093: modification, are permitted provided that the following conditions
1094: are met:
1095:
1096: 1. Redistributions of source code must retain the above copyright
1097: notice, this list of conditions and the following disclaimer.
1098:
1099: 2. Redistributions in binary form must reproduce the above copyright
1100: notice, this list of conditions and the following disclaimer in the
1101: documentation and/or other materials provided with the distribution.
1102:
1103: 3. The name of the author may not be used to endorse or promote products
1104: derived from this software without specific prior written permission.
1105:
1106: THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1107: IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1108: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1109: IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1110: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1111: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1112: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1113: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1114: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1115: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1116: */
|