/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Package /////////////// package org.apache.jena.ontology.impl; // Imports /////////////// import java.util.*; import org.apache.jena.enhanced.* ; import org.apache.jena.graph.* ; import org.apache.jena.graph.compose.Polyadic ; import org.apache.jena.ontology.* ; import org.apache.jena.rdf.model.* ; import org.apache.jena.reasoner.InfGraph ; import org.apache.jena.util.iterator.ExtendedIterator ; import org.apache.jena.vocabulary.* ; /** * <p> * Ontology language profile implementation for the Full variant of the OWL 2002/07 language. * </p> */ public class OWLProfile extends AbstractProfile { // Constants ////////////////////////////////// // Instance variables ////////////////////////////////// // Constructors ////////////////////////////////// // External signature methods ////////////////////////////////// @Override public String NAMESPACE() { return OWL.getURI(); } @Override public Resource CLASS() { return OWL.Class; } @Override public Resource RESTRICTION() { return OWL.Restriction; } @Override public Resource THING() { return OWL.Thing; } @Override public Resource NOTHING() { return OWL.Nothing; } @Override public Resource PROPERTY() { return RDF.Property; } @Override public Resource OBJECT_PROPERTY() { return OWL.ObjectProperty; } @Override public Resource DATATYPE_PROPERTY() { return OWL.DatatypeProperty; } @Override public Resource TRANSITIVE_PROPERTY() { return OWL.TransitiveProperty; } @Override public Resource SYMMETRIC_PROPERTY() { return OWL.SymmetricProperty; } @Override public Resource FUNCTIONAL_PROPERTY() { return OWL.FunctionalProperty; } @Override public Resource INVERSE_FUNCTIONAL_PROPERTY() { return OWL.InverseFunctionalProperty; } @Override public Resource ALL_DIFFERENT() { return OWL.AllDifferent; } @Override public Resource ONTOLOGY() { return OWL.Ontology; } @Override public Resource DEPRECATED_CLASS() { return OWL.DeprecatedClass; } @Override public Resource DEPRECATED_PROPERTY() { return OWL.DeprecatedProperty; } @Override public Resource ANNOTATION_PROPERTY() { return OWL.AnnotationProperty; } @Override public Resource ONTOLOGY_PROPERTY() { return OWL.OntologyProperty; } @Override public Resource LIST() { return RDF.List; } @Override public Resource NIL() { return RDF.nil; } @Override public Resource DATARANGE() { return OWL.DataRange; } @Override public Property EQUIVALENT_PROPERTY() { return OWL.equivalentProperty; } @Override public Property EQUIVALENT_CLASS() { return OWL.equivalentClass; } @Override public Property DISJOINT_WITH() { return OWL.disjointWith; } @Override public Property SAME_INDIVIDUAL_AS() { return null; } @Override public Property SAME_AS() { return OWL.sameAs; } @Override public Property DIFFERENT_FROM() { return OWL.differentFrom; } @Override public Property DISTINCT_MEMBERS() { return OWL.distinctMembers; } @Override public Property UNION_OF() { return OWL.unionOf; } @Override public Property INTERSECTION_OF() { return OWL.intersectionOf; } @Override public Property COMPLEMENT_OF() { return OWL.complementOf; } @Override public Property ONE_OF() { return OWL.oneOf; } @Override public Property ON_PROPERTY() { return OWL.onProperty; } @Override public Property ALL_VALUES_FROM() { return OWL.allValuesFrom; } @Override public Property HAS_VALUE() { return OWL.hasValue; } @Override public Property SOME_VALUES_FROM() { return OWL.someValuesFrom; } @Override public Property MIN_CARDINALITY() { return OWL.minCardinality; } @Override public Property MAX_CARDINALITY() { return OWL.maxCardinality; } @Override public Property CARDINALITY() { return OWL.cardinality; } @Override public Property INVERSE_OF() { return OWL.inverseOf; } @Override public Property IMPORTS() { return OWL.imports; } @Override public Property PRIOR_VERSION() { return OWL.priorVersion; } @Override public Property BACKWARD_COMPATIBLE_WITH() { return OWL.backwardCompatibleWith; } @Override public Property INCOMPATIBLE_WITH() { return OWL.incompatibleWith; } @Override public Property SUB_PROPERTY_OF() { return RDFS.subPropertyOf; } @Override public Property SUB_CLASS_OF() { return RDFS.subClassOf; } @Override public Property DOMAIN() { return RDFS.domain; } @Override public Property RANGE() { return RDFS.range; } @Override public Property FIRST() { return RDF.first; } @Override public Property REST() { return RDF.rest; } @Override public Property MIN_CARDINALITY_Q() { return null; } // qualified restrictions are not in the first version of OWL @Override public Property MAX_CARDINALITY_Q() { return null; } @Override public Property CARDINALITY_Q() { return null; } @Override public Property HAS_CLASS_Q() { return null; } // Annotations @Override public Property VERSION_INFO() { return OWL.versionInfo; } @Override public Property LABEL() { return RDFS.label; } @Override public Property COMMENT() { return RDFS.comment; } @Override public Property SEE_ALSO() { return RDFS.seeAlso; } @Override public Property IS_DEFINED_BY() { return RDFS.isDefinedBy; } @Override protected Resource[][] aliasTable() { return new Resource[][] { }; } /** The only first-class axiom type in OWL is AllDifferent */ @Override public Iterator<Resource> getAxiomTypes() { return Arrays.asList( new Resource[] { OWL.AllDifferent } ).iterator(); } /** The annotation properties of OWL */ @Override public Iterator<Resource> getAnnotationProperties() { return Arrays.asList( new Resource[] { OWL.versionInfo, RDFS.label, RDFS.seeAlso, RDFS.comment, RDFS.isDefinedBy } ).iterator(); } @Override public Iterator<Resource> getClassDescriptionTypes() { return Arrays.asList( new Resource[] { OWL.Class, OWL.Restriction } ).iterator(); } /** * <p> * Answer true if the given graph supports a view of this node as the given * language element, according to the semantic constraints of the profile. * If strict checking on the ontology model is turned off, this check is * skipped. * </p> * * @param n A node to test * @param g The enhanced graph containing <code>n</code>, which is assumed to * be an {@link OntModel}. * @param type A class indicating the facet that we are testing against. * @return True if strict checking is off, or if <code>n</code> can be * viewed according to the facet resource <code>res</code> */ @Override public <T> boolean isSupported( Node n, EnhGraph g, Class<T> type ) { if (g instanceof OntModel) { OntModel m = (OntModel) g; if (!m.strictMode()) { // checking turned off return true; } else { // lookup the profile check for this resource SupportsCheck check = getCheckTable().get( type ); // a check must be defined for the test to succeed return (check != null) && check.doCheck( n, g ); } } else { return false; } } /** * <p> * Answer a descriptive string for this profile, for use in debugging and other output. * </p> * @return "OWL Full" */ @Override public String getLabel() { return "OWL Full"; } // Internal implementation methods ////////////////////////////////// //============================================================================== // Inner class definitions //============================================================================== /** Helper class for doing syntactic/semantic checks on a node */ protected static class SupportsCheck { public boolean doCheck( Node n, EnhGraph g ) { return true; } /** * Return a set of all of the nodes that are the objects of <code>rdf:type</code> * triples whose subject is <code>n</code> * @param n A subject node * @param g A graph * @return All <code>rdf:type</code> nodes for <code>n</code> in <code>g</code> */ public Set<Node> allTypes( Node n, Graph g) { Set<Node> types = new HashSet<>(); for (ExtendedIterator<Triple> i = g.find( n, RDF.type.asNode(), Node.ANY ); i.hasNext(); ) { types.add( i.next().getObject() ); } return types; } /** * Return true if there is any intersection between the nodes in <code>nodes</code> * and the nodes of the resources in <code>ref</code>. * @param nodes * @param ref * @return boolean */ public boolean intersect( Set<Node> nodes, Resource[] ref ) { for (Resource r: ref) { if (nodes.contains( r.asNode() )) { return true; } } return false; } /** * Return true if the node <code>n</code> in graph <code>g</code> has one of the * types in <code>ref</code> */ public boolean hasType( Node n, EnhGraph eg, Resource[] ref ) { // depending on the type of the underlying graph, it may or may not be advantageous // to get all types at once, or ask many separate queries. heuristically, we assume // that fine-grain queries to an inference graph is preferable, and all-at-once for // other types, including persistent stores Graph g = eg.asGraph(); if (isInferenceGraph( g )) { for (Resource r: ref) { if (g.contains( n, RDF.type.asNode(), r.asNode() )) { return true; } } return false; } else { return intersect( allTypes( n, g ), ref ); } } /** * Return true if a given graph is an inference graph * @param g A graph * @return True if the graph is an inference graph, or is a union with an inference * base graph */ public boolean isInferenceGraph( Graph g ) { return (g instanceof InfGraph) || (g instanceof Polyadic && ((Polyadic) g).getBaseGraph() instanceof InfGraph); } } // Table of check data ////////////////////// private static Object[][] s_supportsCheckData = new Object[][] { // Resource (key), check method { AllDifferent.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.AllDifferent.asNode() ); } } }, { AnnotationProperty.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { for (Iterator<Resource> i = ((OntModel) g).getProfile().getAnnotationProperties(); i.hasNext(); ) { if (i.next().asNode().equals( n )) { // a built-in annotation property return true; } } return g.asGraph().contains( n, RDF.type.asNode(), OWL.AnnotationProperty.asNode() ); } } }, { OntClass.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph eg ) { Graph g = eg.asGraph(); return hasType( n, eg, new Resource[] {OWL.Class, OWL.Restriction, RDFS.Class, RDFS.Datatype} ) || // These are common cases that we should support n.equals( OWL.Thing.asNode() ) || n.equals( OWL.Nothing.asNode() ) || g.contains( Node.ANY, RDFS.domain.asNode(), n ) || g.contains( Node.ANY, RDFS.range.asNode(), n ) || g.contains( n, OWL.intersectionOf.asNode(), Node.ANY ) || g.contains( n, OWL.unionOf.asNode(), Node.ANY ) || g.contains( n, OWL.complementOf.asNode(), Node.ANY ) ; } } }, { DatatypeProperty.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.DatatypeProperty.asNode() ); } } }, { ObjectProperty.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return hasType( n, g, new Resource[] {OWL.ObjectProperty,OWL.TransitiveProperty, OWL.SymmetricProperty, OWL.InverseFunctionalProperty} ); } } }, { FunctionalProperty.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.FunctionalProperty.asNode() ); } } }, { InverseFunctionalProperty.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.InverseFunctionalProperty.asNode() ); } } }, { RDFList.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return n.equals( RDF.nil.asNode() ) || g.asGraph().contains( n, RDF.type.asNode(), RDF.List.asNode() ); } } }, { OntProperty.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return hasType( n, g, new Resource[] {RDF.Property, OWL.ObjectProperty, OWL.DatatypeProperty, OWL.AnnotationProperty, OWL.TransitiveProperty, OWL.SymmetricProperty, OWL.InverseFunctionalProperty, OWL.FunctionalProperty} ); } } }, { Ontology.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.Ontology.asNode() ); } } }, { Restriction.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.Restriction.asNode() ); } } }, { HasValueRestriction.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.Restriction.asNode() ) && containsSome( g,n, OWL.hasValue ) && containsSome( g,n, OWL.onProperty ); } } }, { AllValuesFromRestriction.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.Restriction.asNode() ) && containsSome( g, n, OWL.allValuesFrom ) && containsSome( g, n, OWL.onProperty ); } } }, { SomeValuesFromRestriction.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.Restriction.asNode() ) && containsSome( g,n, OWL.someValuesFrom ) && containsSome( g,n, OWL.onProperty ); } } }, { CardinalityRestriction.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.Restriction.asNode() ) && containsSome( g, n, OWL.cardinality ) && containsSome( g, n, OWL.onProperty ); } } }, { MinCardinalityRestriction.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.Restriction.asNode() ) && containsSome( g, n, OWL.minCardinality ) && containsSome( g, n, OWL.onProperty ); } } }, { MaxCardinalityRestriction.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.Restriction.asNode() ) && containsSome( g, n, OWL.maxCardinality ) && containsSome( g, n, OWL.onProperty ); } } }, { SymmetricProperty.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.SymmetricProperty.asNode() ) && !g.asGraph().contains( n, RDF.type.asNode(), OWL.DatatypeProperty.asNode() ); } } }, { TransitiveProperty.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return g.asGraph().contains( n, RDF.type.asNode(), OWL.TransitiveProperty.asNode() ) && !g.asGraph().contains( n, RDF.type.asNode(), OWL.DatatypeProperty.asNode() ); } } }, { Individual.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return n.isURI() || n.isBlank() ; } } }, { DataRange.class, new SupportsCheck() { @Override public boolean doCheck( Node n, EnhGraph g ) { return n.isBlank() && g.asGraph().contains( n, RDF.type.asNode(), OWL.DataRange.asNode() ); } } }}; // to allow concise reference in the code above. public static boolean containsSome( EnhGraph g, Node n, Property p ) { return AbstractProfile.containsSome( g, n, p ); } // Static variables ////////////////////////////////// /** Map from resource to syntactic/semantic checks that a node can be seen as the given facet */ private static HashMap<Class<?>, SupportsCheck> s_supportsChecks = new HashMap<>(); static { // initialise the map of supports checks from a table of static data for ( Object[] aS_supportsCheckData : s_supportsCheckData ) { s_supportsChecks.put( (Class<?>) aS_supportsCheckData[0], (SupportsCheck) aS_supportsCheckData[1] ); } } protected Map<Class<?>, SupportsCheck> getCheckTable() { return s_supportsChecks; } }