org.apache.jena.ontapi.model.OntObject 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.model;
import org.apache.jena.graph.Triple;
import org.apache.jena.ontapi.OntJenaException;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.Statement;
import org.apache.jena.vocabulary.RDF;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
/**
* A base {@link OntResource Ontology Object RDF Resource}.
* A common super-type for all the abstractions in the {@link OntModel Ontology RDF Model},
* which support Jena Polymorphism,
* can be annotated and have a structure strictly defined according to the OWL2 specification.
*/
public interface OntObject extends OntResource {
/**
* Gets a public ont-object type identifier.
*
* @return Class, the actual type of this object
*/
Class extends OntObject> objectType();
/**
* Returns the main {@link OntStatement}
* which determines the nature of this ontological resource.
* In most cases it is a declaration and wraps a triple with predicate {@code rdf:type}.
*
* The returned {@link OntStatement} differs from that
* which could be obtained directly from the model using one of model's {@code statement(..)} methods:
* the main statement annotations are added
* in the form of annotation property assertions (so-called 'plain annotations'),
* not as typed anonymous resources (so-called 'bulk annotations', {@link OntAnnotation}).
* In ONT-API it is legal for a main statement to have both plain and bulk annotations.
* Note: for anonymous ontology objects (i.e., not for OWL Entities) this behavior may not fully meet
* OWL2 specification: the specification describes only bulk annotations
* for all anonymous OWL2 components with except of an individual.
* To get a common ontology statement that supports bulk annotations only,
* the expression {@code getModel().asStatement(this.getMainStatement().asTriple())} can be used.
*
* @return {@link OntStatement} or {@code null} in some boundary cases (e.g., for builtins)
* @see OntModel#asStatement(Triple)
* @see OntStatement#addAnnotation(OntAnnotationProperty, RDFNode)
*/
@Override
OntStatement getMainStatement();
/**
* Lists all characteristic statements of the ontology resource, i.e.,
* all those statements which completely determine this object nature according to the OWL2 specification.
* For non-composite objects the result might contain only the {@link #getMainStatement() root statement}.
* For composite objects (usually anonymous resources: disjoint sections, class expression, etc.)
* the result would contain all statements in the graph directly related to the object
* but without statements that relate to the object components.
* The return stream is ordered and, in most cases,
* the expression {@code this.spec().findFirst().get()} returns the same statement as {@code this.getRoot()}.
* Object annotations are not included in the resultant stream.
*
* For OWL Entities the returned stream will contain only a single main statement
* (i.e. {@link #getMainStatement()}),
* or even will be empty for built-in entities and individuals.
*
* @return {@code Stream} of {@link OntStatement Ontology Statement}s
* @see #content()
*/
@Override
Stream spec();
/**
* Lists the content of the object, i.e., all characteristic statements (see {@link #spec()}),
* plus all additional statements in which this object is the subject,
* minus those of them whose predicate is an annotation property (annotations are not included).
*
* @return {@code Stream} of {@link OntStatement Ontology Statement}s
* @see #spec()
*/
Stream content();
/**
* Adds an ont-statement by attaching predicate and object (value) to this resource.
*
* @param property {@link Property} predicate, not {@code null}
* @param value {@link RDFNode} object, not {@code null}
* @return {@link OntStatement}
* @see Resource#addProperty(Property, RDFNode)
*/
OntStatement addStatement(Property property, RDFNode value);
/**
* Deletes the specific property-value pair from this object.
* All the corresponding statement's annotations are also deleted.
* In case the given {@code object} is {@code null},
* all statements with the {@code property}-predicate will be deleted.
* No-op if no match found.
*
* @param property {@link Property} predicate, not {@code null}
* @param object {@link RDFNode} object, can be {@code null}
* @return this object to allow cascading calls
* @see #addStatement(Property, RDFNode)
* @see OntStatement#clearAnnotations()
*/
OntObject remove(Property property, RDFNode object);
/**
* Lists ont-statements by the predicate.
*
* @param property {@link Property}, predicate, can be {@code null}
* @return {@code Stream} of {@link OntStatement}s
*/
Stream statements(Property property);
/**
* Lists all top-level statements related to this object (i.e., with subject={@code this}).
*
* @return {@code Stream} of all statements
* @see #listProperties()
*/
Stream statements();
/**
* Returns the first statement for the specified property and object.
* What exactly is the first triple is defined at the level of graph; in general, it is unpredictable.
* Also note, the common jena implementation of in-memory graph does not allow duplicated triples,
* and hence there can be at most one operator for a given {@code property} and {@code value}.
*
* @param property {@link Property}, the predicate
* @param value {@link RDFNode}, the object
* @return {@link Optional} around {@link OntStatement}
*/
Optional statement(Property property, RDFNode value);
/**
* Returns the first statement for the specified property.
* What is the first triple is defined at the level of graph; in general, it is unpredictable.
*
* @param property {@link Property}, can be {@code null}
* @return {@link Optional} around {@link OntStatement}
* @see Resource#getProperty(Property)
*/
Optional statement(Property property);
/**
* Lists all objects attached on the property to this object with the given type.
*
* @param predicate {@link Property} predicate, can be {@code null} for wildcard searching
* @param type Interface to find and cast
* @param a class-type of rdf-node
* @return {@code Stream} of {@link RDFNode RDF Node}s of the type {@code O}
*/
Stream objects(Property predicate, Class type);
/**
* Lists all objects attached on the property to this object.
*
* @param predicate {@link Property} predicate, can be {@code null} for wildcard searching
* @return {@code Stream} of {@link RDFNode RDF Node}s
*/
Stream objects(Property predicate);
/**
* Adds an annotation assertion with the given {@link OntAnnotationProperty annotation property} as predicate
* and {@link RDFNode RDF Node} as value.
* The method is equivalent to the expression {@code getRoot().addAnnotation(property, value)}.
*
* @param property {@link OntAnnotationProperty} - named annotation property
* @param value {@link RDFNode} - the value: uri-resource, literal or anonymous individual
* @return {@link OntStatement} for newly added annotation
* to provide the possibility of adding subsequent sub-annotations
* @throws OntJenaException in case input is wrong
* @see OntStatement#addAnnotation(OntAnnotationProperty, RDFNode)
*/
OntStatement addAnnotation(OntAnnotationProperty property, RDFNode value);
/**
* Lists all top-level annotations attached to the root statement of this object.
* Each annotation can be plain (annotation property assertion) or bulk
* (anonymous resource with the type {@code owl:Axiom} or {@code owl:Annotation}, possibly with sub-annotations).
* Sub-annotations are not included in the returned stream.
* For non-built-in ontology objects this is equivalent to the expression {@code getRoot().annotations()}.
*
* @return {@code Stream} of {@link OntStatement}s that have an {@link OntAnnotationProperty annotation property} as predicate
* @see OntStatement#annotations()
* @see OntAnnotation#assertions()
*/
Stream annotations();
/**
* Lists all annotation literals for the given predicate and the language tag.
* Literal tag comparison is case-insensitive.
* Partial search is also allowed, for example,
* a literal with the tag {@code en-GB} will list also if the input language tag is {@code en}.
* An empty string as language tag means searching for plain no-language literals.
*
* @param predicate {@link OntAnnotationProperty}, not {@code null}
* @param lang String, the language tag to restrict the listed literals to,
* or {@code null} to select all literals
* @return {@code Stream} of String's, i.e., literal lexical forms
* @see #annotationValues(OntAnnotationProperty)
*/
Stream annotationValues(OntAnnotationProperty predicate, String lang);
/**
* Removes all root annotations including their sub-annotations hierarchy.
* Any non-root annotations are untouched.
* For example, in case of deleting an OWL class,
* if it is present on the left side of the {@code rdfs:subClassOf} statement,
* all the annotations of that statement will remain in the graph,
* but all main annotations (which belongs to the statement with the predicate {@code rdf:type})
* will be deleted from the graph.
* For non-built-in ontology objects this is equivalent to the expression {@code getRoot().clearAnnotations()}.
*
* @return this object to allow cascading calls
* @see OntStatement#clearAnnotations()
*/
OntObject clearAnnotations();
/**
* Returns the first statement for the specified property.
* What exactly is the first triple is defined at the level of graph and, in general, it is unpredictable.
*
* @param property {@link Property}, the predicate
* @return {@link OntStatement}
* @throws org.apache.jena.shared.PropertyNotFoundException if no such statement found
* @see Resource#getRequiredProperty(Property)
*/
@Override
OntStatement getRequiredProperty(Property property);
/**
* Answers {@code true} iff this object has the declaration triple {@code this rdf:type type},
* where {@code type} is what specified as parameter.
*
* @param type {@link Resource} to test
* @return {@code true} if the given type is present
*/
default boolean hasType(Resource type) {
try (Stream types = types()) {
return types.anyMatch(type::equals);
}
}
/**
* Lists all declarations (statements with {@code rdf:type} predicate).
*
* @return {@code Stream} of {@link Resource}s
*/
default Stream types() {
return objects(RDF.type, Resource.class);
}
/**
* Lists all annotation values for the given predicate.
*
* @param predicate {@link OntAnnotationProperty}, not {@code null}
* @return {@code Stream} of {@link RDFNode}s
* @see #annotations()
*/
default Stream annotationValues(OntAnnotationProperty predicate) {
return annotations()
.filter(s -> Objects.equals(predicate, s.getPredicate()))
.map(Statement::getObject);
}
/**
* Adds no-lang annotation assertion.
*
* @param predicate {@link OntAnnotationProperty} predicate
* @param lexicalForm String, the literal lexical form, not {@code null}
* @return {@link OntStatement}
*/
default OntStatement addAnnotation(OntAnnotationProperty predicate, String lexicalForm) {
return addAnnotation(predicate, lexicalForm, null);
}
/**
* Adds lang annotation assertion.
*
* @param predicate {@link OntAnnotationProperty} predicate
* @param txt String, the literal lexical form, not {@code null}
* @param lang String, the language tag, nullable
* @return {@link OntStatement} - new statement: {@code @subject @predicate "txt"@lang}
*/
default OntStatement addAnnotation(OntAnnotationProperty predicate, String txt, String lang) {
return addAnnotation(predicate, getModel().createLiteral(txt, lang));
}
/**
* Annotates the object with the given {@code predicate} and {@code value}.
*
* @param predicate {@link OntAnnotationProperty} - named annotation property, not {@code null}
* @param value {@link RDFNode} - the value: uri-resource, literal or anonymous individual, not {@code null}
* @return this object to allow cascading calls
* @see OntObject#addAnnotation(OntAnnotationProperty, RDFNode)
*/
default OntObject annotate(OntAnnotationProperty predicate, RDFNode value) {
addAnnotation(predicate, value);
return this;
}
/**
* Adds a language-tagged text for this object and the given {@code predicate}
*
* @param predicate {@link OntAnnotationProperty} - named annotation property, not {@code null}
* @param txt String, the literal lexical form, cannot be {@code null}
* @param lang String, the language tag, can be {@code null}
* @return this object to allow cascading calls
*/
default OntObject annotate(OntAnnotationProperty predicate, String txt, String lang) {
return annotate(predicate, getModel().createLiteral(txt, lang));
}
/**
* Creates {@code _:this rdfs:comment "txt"^^xsd:string} statement.
*
* @param txt String, not {@code null}
* @return this object to allow cascading calls
* @see OntModel#getRDFSComment()
*/
default OntObject addComment(String txt) {
return addComment(txt, null);
}
/**
* Adds the given localized text annotation with builtin {@code rdfs:comment} predicate.
*
* @param txt String, the literal lexical form, not {@code null}
* @param lang String, the language tag, nullable
* @return this object to allow cascading calls
* @see OntModel#getRDFSComment()
*/
default OntObject addComment(String txt, String lang) {
addAnnotation(getModel().getRDFSComment(), txt, lang);
return this;
}
/**
* Creates {@code _:this rdfs:label "txt"^^xsd:string} statement.
*
* @param txt String, the literal lexical form, not {@code null}
* @return this object to allow cascading calls
* @see OntModel#getRDFSLabel()
*/
default OntObject addLabel(String txt) {
return addLabel(txt, null);
}
/**
* Adds the given localized text annotation with builtin {@code rdfs:label} predicate.
*
* @param txt String, the literal lexical form, not {@code null}
* @param lang String, the language tag, nullable
* @return this object to allow cascading calls
* @see OntModel#getRDFSLabel()
*/
default OntObject addLabel(String txt, String lang) {
addAnnotation(getModel().getRDFSLabel(), txt, lang);
return this;
}
/**
* Answers the comment string for this object.
* If there is more than one such resource, an arbitrary selection is made.
*
* @return a {@code rdfs:comment} string or {@code null} if there is no comments
* @see OntModel#getRDFSComment()
*/
default String getComment() {
return getComment(null);
}
/**
* Answers the comment string for this object.
* If there is more than one such resource, an arbitrary selection is made.
*
* @param lang String, the language attribute for the desired comment (EN, FR, etc.) or {@code null} for don't care;
* will attempt to retrieve the most specific comment matching the given language;
* to get no-lang literal string an empty string can be used
* @return a {@code rdfs:comment} string matching the given language,
* or {@code null} if there is no matching comment
* @see OntModel#getRDFSComment()
*/
default String getComment(String lang) {
try (Stream res = annotationValues(getModel().getRDFSComment(), lang)) {
return res.findFirst().orElse(null);
}
}
/**
* Answers the label string for this object.
* If there is more than one such resource, an arbitrary selection is made.
*
* @return a {@code rdfs:label} string or {@code null} if there is no comments
* @see OntModel#getRDFSLabel()
*/
default String getLabel() {
return getLabel(null);
}
/**
* Answers the label string for this object.
* If there is more than one such resource, an arbitrary selection is made.
*
* @param lang String, the language attribute for the desired comment (EN, FR, etc.) or {@code null} for don't care;
* will attempt to retrieve the most specific comment matching the given language;
* to get no-lang literal string an empty string can be used
* @return a {@code rdfs:label} string matching the given language, or {@code null} if there is no matching label
* @see OntModel#getRDFSLabel()
*/
default String getLabel(String lang) {
try (Stream res = annotationValues(getModel().getRDFSLabel(), lang)) {
return res.findFirst().orElse(null);
}
}
}