org.apache.jena.ontapi.impl.objects.OntClassImpl Maven / Gradle / Ivy
/*
* 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 org.apache.jena.ontapi.impl.objects;
import org.apache.jena.datatypes.RDFDatatype;
import org.apache.jena.datatypes.xsd.XSDDatatype;
import org.apache.jena.enhanced.EnhGraph;
import org.apache.jena.graph.Node;
import org.apache.jena.ontapi.OntJenaException;
import org.apache.jena.ontapi.OntModelControls;
import org.apache.jena.ontapi.common.OntEnhGraph;
import org.apache.jena.ontapi.common.OntEnhNodeFactories;
import org.apache.jena.ontapi.common.OntPersonalities;
import org.apache.jena.ontapi.impl.HierarchySupport;
import org.apache.jena.ontapi.impl.OntGraphModelImpl;
import org.apache.jena.ontapi.model.OntClass;
import org.apache.jena.ontapi.model.OntDataProperty;
import org.apache.jena.ontapi.model.OntDataRange;
import org.apache.jena.ontapi.model.OntDisjoint;
import org.apache.jena.ontapi.model.OntIndividual;
import org.apache.jena.ontapi.model.OntList;
import org.apache.jena.ontapi.model.OntModel;
import org.apache.jena.ontapi.model.OntObject;
import org.apache.jena.ontapi.model.OntObjectProperty;
import org.apache.jena.ontapi.model.OntProperty;
import org.apache.jena.ontapi.model.OntRelationalProperty;
import org.apache.jena.ontapi.model.OntStatement;
import org.apache.jena.ontapi.utils.Iterators;
import org.apache.jena.ontapi.utils.StdModels;
import org.apache.jena.rdf.model.Literal;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.RDFList;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.ResourceFactory;
import org.apache.jena.util.iterator.ExtendedIterator;
import org.apache.jena.vocabulary.OWL2;
import org.apache.jena.vocabulary.RDF;
import org.apache.jena.vocabulary.RDFS;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* A base class for any class-expression implementation.
*/
@SuppressWarnings("WeakerAccess")
public abstract class OntClassImpl extends OntObjectImpl implements OntClass {
public OntClassImpl(Node n, EnhGraph m) {
super(n, m);
}
public static boolean isQualified(OntObject c) {
return c != null &&
OntGraphModelImpl.configValue(c.getModel(), OntModelControls.USE_OWL2_QUALIFIED_CARDINALITY_RESTRICTION_FEATURE)
&& !(OWL2.Thing.equals(c) || RDFS.Literal.equals(c));
}
protected static CardinalityType getCardinalityType(Class extends CardinalityRestriction, ?>> view) {
if (ObjectMinCardinality.class.equals(view) || DataMinCardinality.class.equals(view)) {
return CardinalityType.MIN;
}
if (ObjectMaxCardinality.class.equals(view) || DataMaxCardinality.class.equals(view)) {
return CardinalityType.MAX;
}
return CardinalityType.EXACTLY;
}
protected static Literal createNonNegativeIntegerLiteral(int n) {
if (n < 0) throw new OntJenaException.IllegalArgument("Can't accept negative value: " + n);
return ResourceFactory.createTypedLiteral(String.valueOf(n), XSDDatatype.XSDnonNegativeInteger);
}
private static Resource createRestriction(OntModel model) {
return model.createResource(OWL2.Restriction);
}
protected static Resource createOnPropertyRestriction(OntGraphModelImpl model, OntProperty onProperty) {
OntJenaException.notNull(onProperty, "Null property.");
return createRestriction(model).addProperty(OWL2.onProperty, onProperty);
}
public static > CE createComponentRestrictionCE(OntGraphModelImpl model,
Class view,
OntProperty onProperty,
RDFNode other,
Property predicate) {
OntJenaException.notNull(other, "Null expression.");
Resource res = createOnPropertyRestriction(model, onProperty).addProperty(predicate, other);
return model.getNodeAs(res.asNode(), view);
}
public static > CE createCardinalityRestrictionCE(OntGraphModelImpl model,
Class view,
OntProperty onProperty,
int cardinality,
OntObject object) {
Literal value = createNonNegativeIntegerLiteral(cardinality);
Resource res = createOnPropertyRestriction(model, onProperty);
boolean qualified = isQualified(object);
model.add(res, getCardinalityType(view).getPredicate(qualified), value);
if (qualified) {
model.add(res, onProperty instanceof OntObjectProperty ? OWL2.onClass : OWL2.onDataRange, object);
}
return model.getNodeAs(res.asNode(), view);
}
public static > CE createNaryRestrictionCE(OntGraphModelImpl model,
Class type,
OntDataRange dr,
Collection properties) {
NaryRestrictionImpl.validateArity(dr, properties);
Property predicate = NaryDataAllValuesFrom.class.equals(type) ? OWL2.allValuesFrom : OWL2.someValuesFrom;
Resource res = createRestriction(model)
.addProperty(predicate, dr)
.addProperty(OWL2.onProperties, model.createList(properties.iterator()));
return model.getNodeAs(res.asNode(), type);
}
public static , R extends OntObject> CE createComponentsCE(OntGraphModelImpl model,
Class returnType,
Class componentType,
Property predicate,
Stream components) {
OntJenaException.notNull(components, "Null components stream.");
RDFList items = model.createList(components
.peek(x -> OntJenaException.notNull(x,
OntEnhNodeFactories.viewAsString(returnType) + ": null " + OntEnhNodeFactories.viewAsString(componentType) + " member"))
.iterator());
Resource res = model.createResource(OWL2.Class).addProperty(predicate, items);
return model.getNodeAs(res.asNode(), returnType);
}
public static HasSelf createHasSelf(OntGraphModelImpl model, OntObjectProperty onProperty) {
Resource res = createOnPropertyRestriction(model, onProperty).addProperty(OWL2.hasSelf, StdModels.TRUE);
return model.getNodeAs(res.asNode(), HasSelf.class);
}
public static ComplementOf createComplementOf(OntGraphModelImpl model, OntClass other) {
OntJenaException.notNull(other, "Null class expression.");
Resource res = model.createResource(OWL2.Class).addProperty(OWL2.complementOf, other);
return model.getNodeAs(res.asNode(), ComplementOf.class);
}
public static OntIndividual.Anonymous createAnonymousIndividual(OntGraphModelImpl model, OntClass source) {
model.checkType(OntIndividual.Anonymous.class);
OntJenaException.checkSupported(source.canAsAssertionClass(),
"Class " + OntEnhNodeFactories.viewAsString(source.getClass()) + " cannot have individuals. " +
"Profile: " + model.getOntPersonality().getName());
return model.getNodeAs(model.createResource(source).asNode(), OntIndividual.Anonymous.class);
}
public static OntIndividual.Named createNamedIndividual(OntGraphModelImpl model, OntClass source, String uri) {
OntJenaException.notNull(uri, "Null uri");
OntJenaException.checkSupported(source.canAsAssertionClass(),
"Class " + OntEnhNodeFactories.viewAsString(source.getClass()) + " cannot have individuals. " +
"Profile: " + model.getOntPersonality().getName());
Resource res = model.createResource(uri, source);
if (OntGraphModelImpl.configValue(model, OntModelControls.USE_OWL2_NAMED_INDIVIDUAL_DECLARATION_FEATURE)) {
res.addProperty(RDF.type, OWL2.NamedIndividual);
}
return res.as(OntIndividual.Named.class);
}
public static OntList createHasKey(OntGraphModelImpl m,
OntClass clazz,
Stream extends OntRelationalProperty> collection) {
OntGraphModelImpl.checkFeature(m, OntModelControls.USE_OWL2_CLASS_HAS_KEY_FEATURE, "owl:hasKey");
OntJenaException.checkSupported(clazz.canAsSubClass(),
"Class " + OntEnhNodeFactories.viewAsString(clazz.getClass()) + " cannot have keys. " +
"Profile: " + m.getOntPersonality().getName());
return m.createOntList(clazz, OWL2.hasKey, OntRelationalProperty.class,
collection.distinct().map(OntRelationalProperty.class::cast).iterator());
}
public static Stream> listHasKeys(OntGraphModelImpl m, OntClass clazz) {
if (!OntGraphModelImpl.configValue(m, OntModelControls.USE_OWL2_CLASS_HAS_KEY_FEATURE)) {
return Stream.empty();
}
if (!clazz.canAsSubClass()) {
return Stream.empty();
}
return OntListImpl.stream(m, clazz, OWL2.hasKey, OntRelationalProperty.class);
}
public static void removeHasKey(OntGraphModelImpl m,
OntClass clazz,
RDFNode rdfList) throws OntJenaException.IllegalArgument {
OntGraphModelImpl.checkFeature(m, OntModelControls.USE_OWL2_CLASS_HAS_KEY_FEATURE, "owl:hasKey");
if (rdfList == null) {
clazz.hasKeys().toList().forEach(it -> m.deleteOntList(clazz, OWL2.hasKey, it));
} else {
m.deleteOntList(clazz, OWL2.hasKey, clazz.findHasKey(rdfList)
.orElseThrow(() -> new OntJenaException.IllegalArgument("can't find list " + rdfList)));
}
}
public static Stream disjointClasses(OntGraphModelImpl m, OntClass clazz) {
if (!OntGraphModelImpl.configValue(m, OntModelControls.USE_OWL_CLASS_DISJOINT_WITH_FEATURE)) {
return Stream.empty();
}
if (!clazz.canAsDisjointClass()) {
return Stream.empty();
}
return Stream.of(
clazz.objects(OWL2.disjointWith, OntClass.class),
m.statements(null, OWL2.disjointWith, clazz)
.filter(it -> it.getSubject().canAs(OntClass.class))
.map(it -> it.getSubject(OntClass.class)),
clazz.disjoints().flatMap(OntDisjoint::members)
)
.flatMap(it -> it)
.filter(it -> !it.equals(clazz))
.filter(OntClass::canAsDisjointClass)
.map(OntClass::asDisjointClass)
.distinct();
}
public static void addDisjoint(OntGraphModelImpl m, OntClass clazz, OntClass other) {
OntGraphModelImpl.checkFeature(m, OntModelControls.USE_OWL_CLASS_DISJOINT_WITH_FEATURE, "owl:disjointWith");
OntJenaException.checkSupported(clazz.canAsDisjointClass() && other.canAsDisjointClass(),
"Classes " + OntEnhNodeFactories.viewAsString(clazz.getClass()) + " and " + OntEnhNodeFactories.viewAsString(other.getClass()) +
" cannot be disjoint. Profile " + m.getOntPersonality().getName()
);
clazz.addStatement(OWL2.disjointWith, other);
}
public static void removeDisjoint(OntGraphModelImpl m, OntClass clazz, Resource other) {
OntGraphModelImpl.checkFeature(m, OntModelControls.USE_OWL_CLASS_DISJOINT_WITH_FEATURE, "owl:disjointWith");
Objects.requireNonNull(clazz).remove(OWL2.disjointWith, other);
}
public static OntStatement addDisjointWithStatement(OntGraphModelImpl m, OntClass clazz, OntClass other) {
OntGraphModelImpl.checkFeature(m, OntModelControls.USE_OWL_CLASS_DISJOINT_WITH_FEATURE, "owl:disjointWith");
OntJenaException.checkSupported(clazz.canAsDisjointClass() && other.canAsDisjointClass(),
"Classes " + OntEnhNodeFactories.viewAsString(clazz.getClass()) + " and " + OntEnhNodeFactories.viewAsString(other.getClass()) +
" cannot be disjoint. Profile " + m.getOntPersonality().getName()
);
return clazz.addStatement(OWL2.disjointWith, other);
}
public static Stream equivalentClasses(OntGraphModelImpl m, OntClass clazz) {
if (!OntGraphModelImpl.configValue(m, OntModelControls.USE_OWL_CLASS_EQUIVALENT_FEATURE)) {
return Stream.empty();
}
if (!clazz.canAsEquivalentClass()) {
return Stream.empty();
}
return Stream.of(clazz.objects(OWL2.equivalentClass, OntClass.class),
m.statements(null, OWL2.equivalentClass, clazz)
.filter(it -> it.getSubject().canAs(OntClass.class))
.map(it -> it.getSubject(OntClass.class))
)
.flatMap(it -> it)
.filter(it -> !it.equals(clazz))
.filter(OntClass::canAsEquivalentClass)
.map(OntClass::asEquivalentClass)
.distinct();
}
public static OntStatement addEquivalentClass(OntGraphModelImpl m, OntClass clazz, OntClass other) {
OntGraphModelImpl.checkFeature(m, OntModelControls.USE_OWL_CLASS_EQUIVALENT_FEATURE, "owl:equivalentClass");
OntJenaException.checkSupported(clazz.canAsEquivalentClass() && other.canAsEquivalentClass(),
"Classes " + OntEnhNodeFactories.viewAsString(clazz.getClass()) + " and " + OntEnhNodeFactories.viewAsString(other.getClass()) +
" cannot be equivalent. Profile " + m.getOntPersonality().getName()
);
return clazz.addStatement(OWL2.equivalentClass, other);
}
public static void removeEquivalentClass(OntGraphModelImpl m, OntClass clazz, Resource other) {
OntGraphModelImpl.checkFeature(m, OntModelControls.USE_OWL_CLASS_EQUIVALENT_FEATURE, "owl:equivalentClass");
clazz.remove(OWL2.equivalentClass, other);
}
public static Stream declaredProperties(OntClass clazz, boolean direct) {
OntModel m = clazz.getModel();
Stream properties = OntPersonalities.isRDFS(OntEnhGraph.asPersonalityModel(m).getOntPersonality())
? m.ontObjects(OntProperty.class)
: Stream.of(m.objectProperties(), m.dataProperties(), m.annotationProperties()).flatMap(it -> it);
Map> indirectSuperclasses = new HashMap<>();
Function> getIndirectSuperclasses = it ->
indirectSuperclasses.computeIfAbsent(it, x -> x.superClasses(false).collect(Collectors.toSet()));
return properties.distinct().filter(p -> p != null && testDomain(clazz, p, direct, getIndirectSuperclasses));
}
/**
* Answers {@code true} if the {@code clazz} is a domain of {@code property}.
*
* @param clazz {@link OntClass}
* @param property {@link OntProperty}
* @param direct {@code boolean}
* @return {@code boolean}
*/
public static boolean testDomain(OntClass clazz, OntProperty property, boolean direct) {
return testDomain(clazz, property, direct, x -> x.superClasses(false).collect(Collectors.toSet()));
}
protected static boolean testDomain(OntClass clazz,
OntProperty property,
boolean direct,
Function> getIndirectSuperClasses) {
if (isReservedOrBuiltin(property)) {
return false;
}
AtomicBoolean isGlobal = new AtomicBoolean(true);
AtomicBoolean seenDirect = new AtomicBoolean(false);
try (Stream extends Resource> domains = property.domains()) {
if (!domains.allMatch(domain -> {
if (domain.equals(OWL2.Thing) || domain.equals(RDFS.Resource)) {
// there are some well-known values we ignore
return true;
}
isGlobal.set(false);
if (clazz.equals(domain)) {
// if this class is actually in the domain (as opposed to one of this class's
// superclasses), then we've detected the direct property case
seenDirect.set(true);
} else {
// there is a class in the domain of p that is not a superclass of this class
return canProveSuperClass(clazz, domain, getIndirectSuperClasses);
}
return true;
})) {
return false;
}
if (direct) {
// if we're looking for direct props, we must either have seen the direct case
// or it's a global prop and this is a root class
return seenDirect.get() || (isGlobal.get() && clazz.isHierarchyRoot());
}
// not direct, we must either found a global or a superclass prop
// otherwise the 'return false' above would have kicked in
return true;
}
}
/**
* Answers true
* if we can demonstrate
* that the class specified as first parameter class has the second parameter as a superclass.
* If this model has a reasoner, this is equivalent to asking if the subclass relation holds.
* Otherwise, we simulate basic reasoning by searching upwards through the class hierarchy.
*
* @param clazz potential subclass
* @param candidate for superclass of {@code clazz}
* @param getIndirectSuperClasses a function to get indirect superclasses
* @return {@code true} if we can show that {@code candidate} is a superclass of {@code clazz}
*/
protected static boolean canProveSuperClass(OntClass clazz,
Resource candidate,
Function> getIndirectSuperClasses) {
Set seen = new HashSet<>();
Deque queue = new ArrayDeque<>();
queue.add(clazz);
while (!queue.isEmpty()) {
OntClass current = queue.removeFirst();
if (seen.contains(current)) {
continue;
}
seen.add(current);
if (current.equals(candidate)) {
return true;
}
for (OntClass next : getIndirectSuperClasses.apply(current)) {
if (next.equals(candidate)) {
return true;
}
queue.add(next);
}
}
return false;
}
public static boolean isHierarchyRoot(OntClass clazz) {
if (OWL2.Nothing.equals(clazz)) {
return false;
}
try (Stream superClasses = clazz.superClasses(true)) {
return superClasses.allMatch(s -> s.equals(OWL2.Thing) || s.equals(RDFS.Resource) || s.equals(clazz));
}
}
public static boolean isDisjoint(OntClass clazz, Resource candidate) {
if (!candidate.canAs(OntClass.class)) {
return false;
}
if (!clazz.canAsDisjointClass()) {
return false;
}
OntClass other = candidate.as(OntClass.class);
if (!other.canAsDisjointClass()) {
return false;
}
try (Stream disjoints = other.disjointClasses()) {
if (disjoints.anyMatch(clazz::equals)) {
return true;
}
}
try (Stream disjoints = clazz.disjointClasses()) {
if (disjoints.anyMatch(other::equals)) {
return true;
}
}
try (Stream disjoints = clazz.getModel().ontObjects(OntDisjoint.Classes.class)) {
return disjoints.anyMatch(d -> {
Set members = d.members().collect(Collectors.toSet());
return members.contains(clazz) && members.contains(other);
});
}
}
static Stream individuals(OntClass clazz, boolean direct) {
if (!clazz.canAsAssertionClass()) {
return Stream.empty();
}
if (OntGraphModelImpl.configValue(clazz.getModel(), OntModelControls.USE_BUILTIN_HIERARCHY_SUPPORT)) {
// TODO: optimize
return clazz.getModel().individuals().filter(i -> i.hasOntClass(clazz, direct));
}
return subjects(RDF.type, clazz, OntIndividual.class).filter(i -> i.hasOntClass(clazz, direct));
}
public static Stream subClasses(OntClass clazz, boolean direct) {
if (!clazz.canAsSuperClass()) {
return Stream.empty();
}
if (direct) {
Property reasonerProperty = reasonerProperty(clazz.getModel(), RDFS.subClassOf);
if (reasonerProperty != null) {
return explicitSubClasses(reasonerProperty, clazz).filter(x -> !clazz.equals(x));
}
}
return HierarchySupport.treeNodes(
clazz,
it -> explicitSubClasses(RDFS.subClassOf, it),
direct,
OntGraphModelImpl.configValue(clazz.getModel(), OntModelControls.USE_BUILTIN_HIERARCHY_SUPPORT)
);
}
public static Stream superClasses(OntClass clazz, boolean direct) {
if (!clazz.canAsSubClass()) {
return Stream.empty();
}
if (direct) {
Property reasonerProperty = reasonerProperty(clazz.getModel(), RDFS.subClassOf);
if (reasonerProperty != null) {
return explicitSuperClasses(reasonerProperty, clazz).filter(x -> !clazz.equals(x));
}
}
return HierarchySupport.treeNodes(
clazz,
it -> explicitSuperClasses(RDFS.subClassOf, it),
direct,
OntGraphModelImpl.configValue(clazz.getModel(), OntModelControls.USE_BUILTIN_HIERARCHY_SUPPORT)
);
}
public static boolean hasSuperClass(OntClass clazz, OntClass candidateSuper, boolean direct) {
if (clazz.equals(candidateSuper)) {
// every class is a subclass of itself
return true;
}
if (!clazz.canAsSubClass() || !candidateSuper.canAsSuperClass()) {
return false;
}
if (direct) {
Property reasonerProperty = reasonerProperty(clazz.getModel(), RDFS.subClassOf);
if (reasonerProperty != null) {
return clazz.getModel().contains(clazz, reasonerProperty, candidateSuper);
}
}
return HierarchySupport.contains(
clazz,
candidateSuper,
it -> explicitSuperClasses(RDFS.subClassOf, it),
direct,
OntGraphModelImpl.configValue(clazz.getModel(), OntModelControls.USE_BUILTIN_HIERARCHY_SUPPORT)
);
}
static Stream explicitSuperClasses(Property predicate, OntObject clazz) {
return clazz.objects(predicate, OntClass.class).filter(OntClass::canAsSuperClass).map(OntClass::asSuperClass);
}
static Stream explicitSubClasses(OntClass clazz) {
return explicitSubClasses(RDFS.subClassOf, clazz);
}
static Stream explicitSubClasses(Property predicate, OntClass clazz) {
return subjects(predicate, clazz, OntClass.class).filter(OntClass::canAsSubClass).map(OntClass::asSubClass);
}
@Override
public Optional findRootStatement() {
return getRequiredRootStatement(this, OWL2.Class);
}
@Override
public abstract Class extends OntClass> objectType();
@Override
public OntIndividual.Anonymous createIndividual() {
return createAnonymousIndividual(getModel(), this);
}
@Override
public OntIndividual.Named createIndividual(String uri) {
return createNamedIndividual(getModel(), this, uri);
}
@Override
public OntList createHasKey(Collection ope, Collection dpe) {
Stream stream = Stream.concat(ope.stream(), dpe.stream());
return createHasKey(getModel(), this, stream);
}
@Override
public OntStatement addHasKeyStatement(OntRelationalProperty... properties) {
return createHasKey(getModel(), this, Arrays.stream(properties)).getMainStatement();
}
@Override
public Stream> hasKeys() {
return listHasKeys(getModel(), this);
}
@Override
public OntClassImpl removeHasKey(Resource list) throws OntJenaException.IllegalArgument {
removeHasKey(getModel(), this, list);
return this;
}
@Override
public boolean isDisjoint(Resource candidate) {
return isDisjoint(this, candidate);
}
@Override
public Stream disjointClasses() {
return disjointClasses(getModel(), this);
}
@Override
public OntClass addDisjointClass(OntClass other) {
addDisjoint(getModel(), this, other);
return this;
}
@Override
public OntStatement addDisjointWithStatement(OntClass other) {
return addDisjointWithStatement(getModel(), this, other);
}
@Override
public OntClass removeDisjointClass(Resource other) {
removeDisjoint(getModel(), this, other);
return this;
}
@Override
public Stream equivalentClasses() {
return equivalentClasses(getModel(), this);
}
@Override
public boolean hasSuperClass(OntClass clazz, boolean direct) {
return OntClassImpl.hasSuperClass(this, clazz, direct);
}
@Override
public OntStatement addEquivalentClassStatement(OntClass other) {
return addEquivalentClass(getModel(), this, other);
}
@Override
public OntClass removeEquivalentClass(Resource other) {
removeEquivalentClass(getModel(), this, other);
return this;
}
@Override
public Stream superClasses(boolean direct) {
return superClasses(this, direct);
}
@Override
public Stream subClasses(boolean direct) {
return subClasses(this, direct);
}
@Override
public Stream individuals(boolean direct) {
return individuals(this, direct);
}
@Override
public boolean hasDeclaredProperty(OntProperty property, boolean direct) {
return testDomain(this, property, direct);
}
@Override
public Stream declaredProperties(boolean direct) {
return declaredProperties(this, direct);
}
@Override
public boolean isHierarchyRoot() {
return isHierarchyRoot(this);
}
public enum CardinalityType {
EXACTLY(OWL2.qualifiedCardinality, OWL2.cardinality),
MAX(OWL2.maxQualifiedCardinality, OWL2.maxCardinality),
MIN(OWL2.minQualifiedCardinality, OWL2.minCardinality);
static final RDFDatatype NON_NEGATIVE_INTEGER = XSDDatatype.XSDnonNegativeInteger;
static final Node CLASS_REFERENCE = OWL2.onClass.asNode();
static final Node RANGE_REFERENCE = OWL2.onDataRange.asNode();
private final Property qualifiedPredicate, predicate;
CardinalityType(Property qualifiedPredicate, Property predicate) {
this.qualifiedPredicate = qualifiedPredicate;
this.predicate = predicate;
}
private static boolean isObjectOfType(EnhGraph g, Node n, Class extends RDFNode> type) {
return OntEnhGraph.canAs(type, n, g);
}
public static boolean isNonNegativeInteger(Node n) {
return n.isLiteral() && NON_NEGATIVE_INTEGER.equals(n.getLiteralDatatype());
}
public Property getPredicate(boolean isQualified) {
return isQualified ? qualifiedPredicate : predicate;
}
public boolean isQualified(Node s, EnhGraph g, Class extends RDFNode> objectType) {
if (!hasCardinality(s, qualifiedPredicate, g)) {
return false;
}
Node p;
if (objectType == OntClass.class) {
p = CLASS_REFERENCE;
} else if (objectType == OntDataRange.class) {
p = RANGE_REFERENCE;
} else {
return false;
}
return Iterators.findFirst(g.asGraph().find(s, p, Node.ANY)
.filterKeep(t -> isObjectOfType(g, t.getObject(), objectType))).isPresent();
}
public boolean isNonQualified(Node s, EnhGraph g) {
return hasCardinality(s, predicate, g);
}
private boolean hasCardinality(Node s, Property p, EnhGraph g) {
return Iterators.findFirst(g.asGraph().find(s, p.asNode(), Node.ANY)
.filterKeep(t -> isNonNegativeInteger(t.getObject()))).isPresent();
}
}
public static class QLObjectSomeValuesFromImpl extends ObjectSomeValuesFromImpl {
public QLObjectSomeValuesFromImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSubClass() {
if (OWL2.Thing.equals(getValue())) {
return this;
}
throw new OntJenaException.Unsupported("Specification does not allow this class to be a subclass");
}
@Override
public boolean canAsSubClass() {
return OWL2.Thing.equals(getValue());
}
@Override
public OntClass asSuperClass() {
if (getValue().isURIResource()) {
return this;
}
throw new OntJenaException.Unsupported("Specification does not allow this class to be a superclass");
}
@Override
public boolean canAsSuperClass() {
return getValue().isURIResource();
}
@Override
public OntClass asEquivalentClass() {
if (OWL2.Thing.equals(getValue())) {
return this;
}
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent class");
}
@Override
public boolean canAsEquivalentClass() {
return OWL2.Thing.equals(getValue());
}
@Override
public OntClass asDisjointClass() {
if (OWL2.Thing.equals(getValue())) {
return this;
}
throw new OntJenaException.Unsupported("Specification does not allow this class to be a disjoint class");
}
@Override
public boolean canAsDisjointClass() {
return OWL2.Thing.equals(getValue());
}
@Override
public OntClass asAssertionClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a object position of class assertion");
}
@Override
public boolean canAsAssertionClass() {
return false;
}
}
public static class RLObjectSomeValuesFromImpl extends ObjectSomeValuesFromImpl {
public RLObjectSomeValuesFromImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSuperClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a superclass");
}
@Override
public boolean canAsSuperClass() {
return false;
}
@Override
public OntClass asAssertionClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a type of individual");
}
@Override
public boolean canAsAssertionClass() {
return false;
}
@Override
public OntClass asEquivalentClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent");
}
@Override
public boolean canAsEquivalentClass() {
return false;
}
}
public static class ObjectSomeValuesFromImpl
extends ComponentRestrictionImpl implements ObjectSomeValuesFrom {
public ObjectSomeValuesFromImpl(Node n, EnhGraph m) {
super(n, m, OWL2.someValuesFrom, OntClass.class, OntObjectProperty.class);
}
@Override
public Class objectType() {
return ObjectSomeValuesFrom.class;
}
}
public static class QLDataSomeValuesFromImpl extends DataSomeValuesFromImpl {
public QLDataSomeValuesFromImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asAssertionClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a object position of class assertion");
}
@Override
public boolean canAsAssertionClass() {
return false;
}
}
public static class RLDataSomeValuesFromImpl extends DataSomeValuesFromImpl {
public RLDataSomeValuesFromImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSuperClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a superclass");
}
@Override
public boolean canAsSuperClass() {
return false;
}
@Override
public OntClass asAssertionClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a type of individual");
}
@Override
public boolean canAsAssertionClass() {
return false;
}
@Override
public OntClass asEquivalentClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent class");
}
@Override
public boolean canAsEquivalentClass() {
return false;
}
}
public static class DataSomeValuesFromImpl
extends ComponentRestrictionImpl implements DataSomeValuesFrom {
public DataSomeValuesFromImpl(Node n, EnhGraph m) {
super(n, m, OWL2.someValuesFrom, OntDataRange.class, OntDataProperty.class);
}
@Override
public Class objectType() {
return DataSomeValuesFrom.class;
}
}
public static class RLObjectAllValuesFromImpl extends ObjectAllValuesFromImpl {
public RLObjectAllValuesFromImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSubClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a subclass");
}
@Override
public boolean canAsSubClass() {
return false;
}
@Override
public OntClass asEquivalentClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent class");
}
@Override
public boolean canAsEquivalentClass() {
return false;
}
@Override
public OntClass asDisjointClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a disjoint class");
}
@Override
public boolean canAsDisjointClass() {
return false;
}
}
public static class ObjectAllValuesFromImpl
extends ComponentRestrictionImpl implements ObjectAllValuesFrom {
public ObjectAllValuesFromImpl(Node n, EnhGraph m) {
super(n, m, OWL2.allValuesFrom, OntClass.class, OntObjectProperty.class);
}
@Override
public Class objectType() {
return ObjectAllValuesFrom.class;
}
}
public static class RLDataAllValuesFromImpl extends DataAllValuesFromImpl {
public RLDataAllValuesFromImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSubClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a subclass");
}
@Override
public boolean canAsSubClass() {
return false;
}
@Override
public OntClass asEquivalentClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent class");
}
@Override
public boolean canAsEquivalentClass() {
return false;
}
@Override
public OntClass asDisjointClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a disjoint class");
}
@Override
public boolean canAsDisjointClass() {
return false;
}
}
public static class DataAllValuesFromImpl
extends ComponentRestrictionImpl implements DataAllValuesFrom {
public DataAllValuesFromImpl(Node n, EnhGraph m) {
super(n, m, OWL2.allValuesFrom, OntDataRange.class, OntDataProperty.class);
}
@Override
public Class objectType() {
return DataAllValuesFrom.class;
}
}
public static class ObjectHasValueImpl
extends ComponentRestrictionImpl implements ObjectHasValue {
public ObjectHasValueImpl(Node n, EnhGraph m) {
super(n, m, OWL2.hasValue, OntIndividual.class, OntObjectProperty.class);
}
@Override
public Class objectType() {
return ObjectHasValue.class;
}
}
public static class DataHasValueImpl
extends ComponentRestrictionImpl implements DataHasValue {
public DataHasValueImpl(Node n, EnhGraph m) {
super(n, m, OWL2.hasValue, Literal.class, OntDataProperty.class);
}
@Override
public Class objectType() {
return DataHasValue.class;
}
}
public static class RLUnionOfImpl extends UnionOfImpl {
public RLUnionOfImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSuperClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a superclass");
}
@Override
public boolean canAsSuperClass() {
return false;
}
@Override
public OntClass asEquivalentClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent class");
}
@Override
public boolean canAsEquivalentClass() {
return false;
}
@Override
public Stream components() {
return getList().members().filter(OntClass::canAsSubClass);
}
}
public static class UnionOfImpl extends CollectionOfImpl implements UnionOf {
public UnionOfImpl(Node n, EnhGraph m) {
super(n, m, OWL2.unionOf, OntClass.class);
}
@Override
public Class objectType() {
return UnionOf.class;
}
}
public static class QLIntersectionOfImpl extends IntersectionOfImpl {
public QLIntersectionOfImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSubClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a subclass");
}
@Override
public boolean canAsSubClass() {
return false;
}
@Override
public OntClass asAssertionClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a object position of class assertion");
}
@Override
public boolean canAsAssertionClass() {
return false;
}
@Override
public OntClass asEquivalentClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent class");
}
@Override
public boolean canAsEquivalentClass() {
return false;
}
@Override
public OntClass asDisjointClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a disjoint class");
}
@Override
public boolean canAsDisjointClass() {
return false;
}
@Override
public Stream components() {
return getList().members().filter(OntClass::canAsSuperClass).map(OntClass::asSuperClass);
}
}
/**
* @see RL: Class Expressions
*/
public static class RLIntersectionOfImpl extends IntersectionOfImpl {
public RLIntersectionOfImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSubClass() {
return asSubClass(() -> "Specification does not allow this class to be a subclass");
}
@Override
public boolean canAsSubClass() {
return hasMemberSubClasses();
}
@Override
public OntClass asSuperClass() {
return asSuperClass(() -> "Specification does not allow this class to be a superclass");
}
@Override
public boolean canAsSuperClass() {
return hasMemberSuperClasses();
}
@Override
public OntClass asEquivalentClass() {
Collection res = collectEquivalentClasses();
if (res.isEmpty()) {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent class");
}
return new RLIntersectionOfImpl(this.node, this.enhGraph) {
@Override
public Stream components() {
return res.stream();
}
};
}
@Override
public boolean canAsEquivalentClass() {
return hasMemberEquivalentClasses();
}
@Override
public OntClass asAssertionClass() {
return asSuperClass(() -> "Specification does not allow this class to be a type of individual");
}
@Override
public boolean canAsAssertionClass() {
return hasMemberSuperClasses();
}
@Override
public OntClass asDisjointClass() {
return asSubClass(() -> "Specification does not allow this class to be a disjoint class");
}
@Override
public boolean canAsDisjointClass() {
return hasMemberSubClasses();
}
private OntClass asSuperClass(Supplier message) {
Collection res = collectMemberSuperClasses();
if (res.isEmpty()) {
throw new OntJenaException.Unsupported(message.get());
}
return new RLIntersectionOfImpl(this.node, this.enhGraph) {
@Override
public Stream components() {
return res.stream();
}
};
}
private OntClass asSubClass(Supplier message) {
Collection res = collectMemberSubClasses();
if (res.isEmpty()) {
throw new OntJenaException.Unsupported(message.get());
}
return new RLIntersectionOfImpl(this.node, this.enhGraph) {
@Override
public Stream components() {
return res.stream();
}
};
}
private Collection collectMemberSubClasses() {
Set res = new LinkedHashSet<>();
getList().members().forEach(it -> {
if (it.canAsSubClass()) {
res.add(it.asSubClass());
}
});
return res.size() > 1 ? res : List.of();
}
private Collection collectMemberSuperClasses() {
Set res = new LinkedHashSet<>();
getList().members().forEach(it -> {
if (it.canAsSuperClass()) {
res.add(it.asSuperClass());
}
});
return res.size() > 1 ? res : List.of();
}
private Collection collectEquivalentClasses() {
Set res = new LinkedHashSet<>();
getList().members().forEach(it -> {
if (it.canAsEquivalentClass()) {
res.add(it.asEquivalentClass());
}
});
return res.size() > 1 ? res : List.of();
}
private boolean hasMemberSubClasses() {
try (Stream members = getList().members().filter(OntClass::canAsSubClass)) {
return Iterators.hasAtLeast(members.iterator(), 2);
}
}
private boolean hasMemberSuperClasses() {
try (Stream members = getList().members().filter(OntClass::canAsSuperClass)) {
return Iterators.hasAtLeast(members.iterator(), 2);
}
}
private boolean hasMemberEquivalentClasses() {
try (Stream members = getList().members().filter(OntClass::canAsEquivalentClass)) {
return Iterators.hasAtLeast(members.iterator(), 2);
}
}
}
public static class IntersectionOfImpl extends CollectionOfImpl implements IntersectionOf {
public IntersectionOfImpl(Node n, EnhGraph m) {
super(n, m, OWL2.intersectionOf, OntClass.class);
}
@Override
public Class objectType() {
return IntersectionOf.class;
}
}
public static class RLOneOfImpl extends OneOfImpl {
public RLOneOfImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSuperClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a superclass");
}
@Override
public boolean canAsSuperClass() {
return false;
}
@Override
public OntClass asAssertionClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a type of individual");
}
@Override
public boolean canAsAssertionClass() {
return false;
}
@Override
public OntClass asEquivalentClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent class");
}
@Override
public boolean canAsEquivalentClass() {
return false;
}
}
public static class OneOfImpl extends CollectionOfImpl implements OneOf {
public OneOfImpl(Node n, EnhGraph m) {
super(n, m, OWL2.oneOf, OntIndividual.class);
}
@Override
public Class objectType() {
return OneOf.class;
}
}
public static class DataMinCardinalityImpl
extends CardinalityRestrictionImpl implements DataMinCardinality {
public DataMinCardinalityImpl(Node n, EnhGraph m) {
super(n, m, OWL2.onDataRange, OntDataRange.class, OntDataProperty.class, CardinalityType.MIN);
}
@Override
public Class objectType() {
return DataMinCardinality.class;
}
}
public static class ObjectMinCardinalityImpl
extends CardinalityRestrictionImpl implements ObjectMinCardinality {
public ObjectMinCardinalityImpl(Node n, EnhGraph m) {
super(n, m, OWL2.onClass, OntClass.class, OntObjectProperty.class, CardinalityType.MIN);
}
@Override
public Class objectType() {
return ObjectMinCardinality.class;
}
}
public static class RLDataMaxCardinalityImpl extends DataMaxCardinalityImpl {
public RLDataMaxCardinalityImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSubClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a subclass");
}
@Override
public boolean canAsSubClass() {
return false;
}
@Override
public OntClass asEquivalentClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent class");
}
@Override
public boolean canAsEquivalentClass() {
return false;
}
@Override
public OntClass asDisjointClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a disjoint class");
}
@Override
public boolean canAsDisjointClass() {
return false;
}
}
public static class DataMaxCardinalityImpl
extends CardinalityRestrictionImpl implements DataMaxCardinality {
public DataMaxCardinalityImpl(Node n, EnhGraph m) {
super(n, m, OWL2.onDataRange, OntDataRange.class, OntDataProperty.class, CardinalityType.MAX);
}
@Override
public Class objectType() {
return DataMaxCardinality.class;
}
}
public static class RLObjectMaxCardinalityImpl extends ObjectMaxCardinalityImpl {
public RLObjectMaxCardinalityImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSubClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a subclass");
}
@Override
public boolean canAsSubClass() {
return false;
}
@Override
public OntClass asEquivalentClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent class");
}
@Override
public boolean canAsEquivalentClass() {
return false;
}
@Override
public OntClass asDisjointClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a disjoint class");
}
@Override
public boolean canAsDisjointClass() {
return false;
}
}
public static class ObjectMaxCardinalityImpl
extends CardinalityRestrictionImpl implements ObjectMaxCardinality {
public ObjectMaxCardinalityImpl(Node n, EnhGraph m) {
super(n, m, OWL2.onClass, OntClass.class, OntObjectProperty.class, CardinalityType.MAX);
}
@Override
public Class objectType() {
return ObjectMaxCardinality.class;
}
}
public static class DataCardinalityImpl
extends CardinalityRestrictionImpl implements DataCardinality {
public DataCardinalityImpl(Node n, EnhGraph m) {
super(n, m, OWL2.onDataRange, OntDataRange.class, OntDataProperty.class, CardinalityType.EXACTLY);
}
@Override
public Class objectType() {
return DataCardinality.class;
}
}
public static class ObjectCardinalityImpl
extends CardinalityRestrictionImpl implements ObjectCardinality {
public ObjectCardinalityImpl(Node n, EnhGraph m) {
super(n, m, OWL2.onClass, OntClass.class, OntObjectProperty.class, CardinalityType.EXACTLY);
}
@Override
public Class objectType() {
return ObjectCardinality.class;
}
}
public static class HasSelfImpl extends OnPropertyRestrictionImpl implements HasSelf {
public HasSelfImpl(Node n, EnhGraph m) {
super(n, m, OntObjectProperty.class);
}
@Override
public ExtendedIterator listSpec() {
return Iterators.concat(super.listSpec(), listRequired(OWL2.hasSelf));
}
@Override
public Class objectType() {
return HasSelf.class;
}
}
public static class QLComplementOfImpl extends ComplementOfImpl {
public QLComplementOfImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSubClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a subclass");
}
@Override
public boolean canAsSubClass() {
return false;
}
@Override
public boolean canAsSuperClass() {
return getValue().canAsSubClass();
}
@Override
public OntClass asAssertionClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an individual type");
}
@Override
public boolean canAsAssertionClass() {
return false;
}
}
public static class RLComplementOfImpl extends ComplementOfImpl {
public RLComplementOfImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public OntClass asSubClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a subclass");
}
@Override
public boolean canAsSubClass() {
return false;
}
@Override
public OntClass asSuperClass() {
if (getValue().canAsSubClass()) {
return this;
}
throw new OntJenaException.Unsupported("Specification does not allow this class to be an super class");
}
@Override
public boolean canAsSuperClass() {
return getValue().canAsSubClass();
}
@Override
public OntClass asAssertionClass() {
if (getValue().canAsSubClass()) {
return this;
}
throw new OntJenaException.Unsupported("Specification does not allow this class to be an individual type");
}
@Override
public boolean canAsAssertionClass() {
return getValue().canAsSubClass();
}
@Override
public OntClass asEquivalentClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be an equivalent class");
}
@Override
public boolean canAsEquivalentClass() {
return false;
}
@Override
public OntClass asDisjointClass() {
throw new OntJenaException.Unsupported("Specification does not allow this class to be a disjoint class");
}
@Override
public boolean canAsDisjointClass() {
return false;
}
}
public static class ComplementOfImpl extends OntClassImpl implements ComplementOf {
public ComplementOfImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public ExtendedIterator listSpec() {
return Iterators.concat(super.listSpec(), listRequired(OWL2.complementOf));
}
@Override
public Class objectType() {
return ComplementOf.class;
}
@Override
public OntClass getValue() {
return getRequiredObject(OWL2.complementOf, OntClass.class);
}
@Override
public ComplementOfImpl setValue(OntClass c) {
Objects.requireNonNull(c, "Null component");
clear();
addProperty(OWL2.complementOf, c);
return this;
}
void clear() {
removeAll(OWL2.complementOf);
}
}
public static class NaryDataAllValuesFromImpl
extends NaryRestrictionImpl implements NaryDataAllValuesFrom {
public NaryDataAllValuesFromImpl(Node n, EnhGraph m) {
super(n, m, OWL2.allValuesFrom, OntDataRange.class, OntDataProperty.class);
}
@Override
public Class extends OntClass> objectType() {
return NaryDataAllValuesFrom.class;
}
}
public static class NaryDataSomeValuesFromImpl
extends NaryRestrictionImpl implements NaryDataSomeValuesFrom {
public NaryDataSomeValuesFromImpl(Node n, EnhGraph m) {
super(n, m, OWL2.someValuesFrom, OntDataRange.class, OntDataProperty.class);
}
@Override
public Class extends OntClass> objectType() {
return NaryDataSomeValuesFrom.class;
}
}
/**
* An abstract superclass for {@link IntersectionOf}, {@link OneOf}, {@link UnionOf}.
*
* @param {@link OntObject}
*/
protected static abstract class CollectionOfImpl
extends OntClassImpl implements CollectionOf {
protected final Property predicate;
protected final Class type;
protected CollectionOfImpl(Node n, EnhGraph m, Property predicate, Class type) {
super(n, m);
this.predicate = OntJenaException.notNull(predicate, "Null predicate.");
this.type = OntJenaException.notNull(type, "Null view.");
}
@Override
public ExtendedIterator listSpec() {
return Iterators.concat(super.listSpec(), getList().listContent());
}
@Override
public OntListImpl getList() {
return getModel().asOntList(getRequiredObject(predicate, RDFList.class), this, predicate, true, null, type);
}
}
/**
* Base for all {@link Restriction} impls.
*/
@SuppressWarnings("javadoc")
public static class RestrictionImpl extends OntClassImpl implements Restriction {
public RestrictionImpl(Node n, EnhGraph m) {
super(n, m);
}
@Override
public Optional findRootStatement() {
return getRequiredRootStatement(this, OWL2.Restriction);
}
@Override
public Class extends OntClass> objectType() {
return OntClass.Restriction.class;
}
}
/**
* Abstract implementation for any restriction with {@code owl:onProperty} predicate.
* Can be used instantiate directly if config settings allow.
*
* @param a subtype of {@link OntRelationalProperty Data or Object Property Expression}
* @param return type for {@link OWL2#onProperty} setter
*/
public static class OnPropertyRestrictionImpl
extends RestrictionImpl implements UnaryRestriction
{
protected final Class
propertyView;
/**
* @param n {@link Node}
* @param m {@link EnhGraph}
* @param propertyType Class-type for {@link OntRelationalProperty}
*/
public OnPropertyRestrictionImpl(Node n, EnhGraph m, Class
propertyType) {
super(n, m);
this.propertyView = propertyType;
}
@Override
public Class extends OntClass> objectType() {
return OntClass.UnaryRestriction.class;
}
@Override
public P getProperty() {
return getRequiredObject(OWL2.onProperty, propertyView);
}
@SuppressWarnings("unchecked")
public R setProperty(P property) {
Objects.requireNonNull(property, "Null " + OntEnhNodeFactories.viewAsString(propertyView));
removeAll(OWL2.onProperty).addProperty(OWL2.onProperty, property);
return (R) this;
}
@Override
public ExtendedIterator listSpec() {
return Iterators.concat(super.listSpec(), listRequired(OWL2.onProperty));
}
}
/**
* Abstract base component-restriction class.
* It's for CE which has owl:onProperty and some component also
* (with predicate owl:dataRange, owl:onClass, owl:someValuesFrom, owl:allValuesFrom)
*
* @param a class-type of {@link RDFNode rdf-node}
* @param a class-type of {@link OntRelationalProperty data or object property-expression}
* @param a subtype of {@link ComponentRestrictionImpl}
*/
public static abstract class ComponentRestrictionImpl>
extends OnPropertyRestrictionImpl implements ComponentRestriction {
protected final Property predicate;
protected final Class objectView;
/**
* @param n Node
* @param m EnhGraph
* @param predicate predicate for value
* @param objectView Class
* @param propertyView Class
*/
protected ComponentRestrictionImpl(Node n,
EnhGraph m,
Property predicate,
Class objectView,
Class propertyView) {
super(n, m, propertyView);
this.predicate = OntJenaException.notNull(predicate, "Null predicate.");
this.objectView = OntJenaException.notNull(objectView, "Null object view.");
}
@Override
public ExtendedIterator listSpec() {
return listSpec(true);
}
protected ExtendedIterator listSpec(boolean requireObject) {
return requireObject ? Iterators.concat(super.listSpec(), listRequired(predicate)) : super.listSpec();
}
@Override
public O getValue() {
return getModel().getNodeAs(getRequiredProperty(predicate).getObject().asNode(), objectView);
}
@SuppressWarnings("unchecked")
public R setValue(O c) {
Objects.requireNonNull(c, "Null filler");
removeAll(predicate).addProperty(predicate, c);
return (R) this;
}
}
/**
* Abstraction for any cardinality restriction.
*
* @param either {@link OntClass} (predicate {@link OWL2#onClass owl:onClass}) or {@link OntDataRange}
* (predicate: {@link OWL2#onDataRange owl:onDataRange})
* @param either {@link OntObjectProperty} or {@link OntDataProperty}
* @param subtype of {@link CardinalityRestrictionImpl}
*/
public static abstract class CardinalityRestrictionImpl>
extends ComponentRestrictionImpl implements CardinalityRestriction {
protected final CardinalityType cardinalityType;
/**
* @param n {@link Node}
* @param m {@link EnhGraph}
* @param predicate either {@code owl:onDataRange} or {@code owl:onClass}
* @param objectView interface of class expression or data range
* @param propertyView interface, property expression
* @param cardinalityType type of cardinality.
*/
protected CardinalityRestrictionImpl(Node n,
EnhGraph m,
Property predicate,
Class objectView,
Class propertyView,
CardinalityType cardinalityType) {
super(n, m, predicate, objectView, propertyView);
this.cardinalityType = cardinalityType;
}
@Override
public ExtendedIterator listSpec() {
// note: object value is null for non-qualified restrictions.
boolean q;
return Iterators.concat(super.listSpec(q = isQualified()), listRequired(getCardinalityPredicate(q)));
}
@Override
public O getValue() { // null for non-qualified restrictions:
return object(predicate, objectView).orElseGet(this::getUnqualifiedValue);
}
@SuppressWarnings("unchecked")
@Override
public R setValue(O value) {
Literal c = getCardinalityLiteral();
removeAll(predicate);
if (!isQualified(value)) { // null, owl:Thing, rdfs:Label
removeAll(getCardinalityPredicate(true))
.addProperty(getCardinalityPredicate(false), c);
} else {
removeAll(getCardinalityPredicate(false))
.addProperty(getCardinalityPredicate(true), c)
.addProperty(predicate, value);
}
return (R) this;
}
@SuppressWarnings("unchecked")
private O getUnqualifiedValue() {
OntModel m = getModel();
OntObject res = OntClass.class.isAssignableFrom(objectView) ? m.getOWLThing() : m.getRDFSLiteral();
return (O) res;
}
@Override
public int getCardinality() {
return getCardinalityLiteral().getInt();
}
@SuppressWarnings("unchecked")
public R setCardinality(int cardinality) {
Literal value = createNonNegativeIntegerLiteral(cardinality);
Property property = getCardinalityPredicate();
removeAll(property).addLiteral(property, value);
return (R) this;
}
private Literal getCardinalityLiteral() {
return getRequiredObject(getCardinalityPredicate(), Literal.class);
}
protected Property getCardinalityPredicate() {
return getCardinalityPredicate(isQualified());
}
private Property getCardinalityPredicate(boolean q) {
return cardinalityType.getPredicate(q);
}
@Override
public boolean isQualified() {
return isQualified(getValue()) && hasProperty(cardinalityType.getPredicate(true));
}
}
public static abstract class NaryRestrictionImpl>
extends OntClassImpl implements NaryRestriction {
protected final Property predicate;
protected final Class objectType; // always OntDR
protected final Class propertyType;
protected NaryRestrictionImpl(Node n,
EnhGraph m,
Property predicate,
Class objectType,
Class propertyType) {
super(n, m);
this.predicate = predicate;
this.objectType = objectType;
this.propertyType = propertyType;
}
public static void validateArity(OntDataRange dr, Collection properties) {
properties.forEach(x -> OntJenaException.notNull(x, "Null data property"));
if (dr.arity() == properties.size()) return;
throw new OntJenaException.IllegalArgument("The number of data properties (" + properties.size() + ") " +
"must be equal to the data range arity (" + dr.arity() + ").");
}
@Override
public Optional findRootStatement() {
return getRequiredRootStatement(this, OWL2.Restriction);
}
@Override
public O getValue() {
return getRequiredObject(predicate, objectType);
}
@SuppressWarnings("unchecked")
public R setValue(O value) {
Objects.requireNonNull(value);
removeAll(predicate).addProperty(predicate, value);
return (R) this;
}
@SuppressWarnings("unchecked")
public R setComponents(Collection properties) {
validateArity((OntDataRange) getValue(), (Collection) properties);
getList().clear().addAll(properties);
return (R) this;
}
@Override
public Class extends OntClass> objectType() {
return NaryRestriction.class;
}
@Override
public ExtendedIterator listSpec() {
return Iterators.concat(super.listSpec(), listRequired(predicate), getList().listContent());
}
@Override
public OntListImpl getList() {
return getModel().asOntList(getRequiredObject(OWL2.onProperties, RDFList.class),
this, OWL2.onProperties, propertyType);
}
}
}