All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.jena.ontapi.impl.objects.OntIndividualImpl 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.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.impl.HierarchySupport;
import org.apache.jena.ontapi.impl.OntGraphModelImpl;
import org.apache.jena.ontapi.model.OntClass;
import org.apache.jena.ontapi.model.OntIndividual;
import org.apache.jena.ontapi.model.OntNegativeAssertion;
import org.apache.jena.ontapi.model.OntObject;
import org.apache.jena.ontapi.model.OntStatement;
import org.apache.jena.ontapi.utils.Iterators;
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.util.iterator.ExtendedIterator;
import org.apache.jena.vocabulary.OWL2;
import org.apache.jena.vocabulary.RDF;
import org.apache.jena.vocabulary.RDFS;

import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * An {@link OntIndividual} implementation, both for anonymous and named individuals.
 */
@SuppressWarnings("WeakerAccess")
public abstract class OntIndividualImpl extends OntObjectImpl implements OntIndividual {

    public OntIndividualImpl(Node n, EnhGraph m) {
        super(n, m);
    }

    public static Anonymous createAnonymousIndividual(RDFNode node) {
        if (OntJenaException.notNull(node, "Null node.").canAs(Anonymous.class))
            return node.as(Anonymous.class);
        if (node.isAnon()) {
            return new AnonymousImpl(node.asNode(), (EnhGraph) node.getModel());
        }
        throw new OntJenaException.Conversion(node + " can't be presented as an anonymous individual");
    }

    /**
     * Returns a {@code Stream} of all class-types,
     * including their super-classes if the parameter {@code direct} is {@code false}.
     *
     * @param direct if {@code true} returns only direct types
     * @return a {@code Stream} of all {@link OntClass class}-types
     */
    @Override
    public Stream classes(boolean direct) {
        return classes(this, direct);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean hasOntClass(OntClass clazz, boolean direct) {
        if (direct) {
            Property reasonerProperty = reasonerProperty(getModel(), RDF.type);
            if (reasonerProperty != null) {
                return getModel().contains(this, reasonerProperty, clazz);
            }
        }
        AtomicBoolean isIndividual = new AtomicBoolean(true);
        return HierarchySupport.contains(
                this,
                (OntObject) clazz,
                it -> (Stream) ((Stream) listClassesFor(it, isIndividual)),
                direct,
                OntGraphModelImpl.configValue(getModel(), OntModelControls.USE_BUILTIN_HIERARCHY_SUPPORT)
        );
    }

    @Override
    public Stream sameIndividuals() {
        if (!OntGraphModelImpl.configValue(getModel(), OntModelControls.USE_OWL_INDIVIDUAL_SAME_AS_FEATURE)) {
            return Stream.empty();
        }
        return objects(OWL2.sameAs, OntIndividual.class);
    }

    @Override
    public OntStatement addSameAsStatement(OntIndividual other) {
        OntGraphModelImpl.checkFeature(getModel(), OntModelControls.USE_OWL_INDIVIDUAL_SAME_AS_FEATURE, "owl:sameAs");
        return addStatement(OWL2.sameAs, other);
    }

    @Override
    public OntIndividual removeSameIndividual(Resource other) {
        OntGraphModelImpl.checkFeature(getModel(), OntModelControls.USE_OWL_INDIVIDUAL_SAME_AS_FEATURE, "owl:sameAs");
        remove(OWL2.sameAs, other);
        return this;
    }

    @Override
    public Stream differentIndividuals() {
        if (!OntGraphModelImpl.configValue(getModel(), OntModelControls.USE_OWL_INDIVIDUAL_DIFFERENT_FROM_FEATURE)) {
            return Stream.empty();
        }
        return objects(OWL2.differentFrom, OntIndividual.class);
    }

    @Override
    public OntStatement addDifferentFromStatement(OntIndividual other) {
        OntGraphModelImpl.checkFeature(getModel(), OntModelControls.USE_OWL_INDIVIDUAL_DIFFERENT_FROM_FEATURE, "owl:differentFrom");
        return addStatement(OWL2.differentFrom, other);
    }

    @Override
    public OntIndividual removeDifferentIndividual(Resource other) {
        OntGraphModelImpl.checkFeature(getModel(), OntModelControls.USE_OWL_INDIVIDUAL_DIFFERENT_FROM_FEATURE, "owl:differentFrom");
        remove(OWL2.differentFrom, other);
        return this;
    }

    /**
     * Lists all right parts from class assertion statements where this individual is at subject position.
     *
     * @return {@link ExtendedIterator} over all direct {@link OntClass class}-types
     */
    public ExtendedIterator listClasses() {
        return listObjects(RDF.type, OntClass.class);
    }

    @SuppressWarnings("unchecked")
    static Stream classes(OntObject individual, boolean direct) {
        if (direct) {
            Property reasonerProperty = reasonerProperty(individual.getModel(), RDF.type);
            if (reasonerProperty != null) {
                return individual
                        .objects(reasonerProperty, OntClass.class)
                        .filter(OntClass::canAsAssertionClass)
                        .map(OntClass::asAssertionClass);
            }
        }
        AtomicBoolean isIndividual = new AtomicBoolean(true);
        Stream res = HierarchySupport.treeNodes(individual,
                it -> (Stream) ((Stream) listClassesFor(it, isIndividual)),
                direct,
                OntGraphModelImpl.configValue(individual.getModel(), OntModelControls.USE_BUILTIN_HIERARCHY_SUPPORT)
        );

        return ((Stream) res)
                .filter(OntClass::canAsAssertionClass).map(OntClass::asAssertionClass);
    }

    static Stream listClassesFor(OntObject resource, AtomicBoolean isFirstLevel) {
        if (isFirstLevel.get()) {
            isFirstLevel.set(false);
            return resource
                    .objects(RDF.type, OntClass.class)
                    .filter(OntClass::canAsAssertionClass)
                    .map(OntClass::asAssertionClass);
        }
        return OntClassImpl.explicitSuperClasses(RDFS.subClassOf, resource);
    }

    @Override
    public boolean isLocal() {
        Optional root = findRootStatement();
        return (root.isPresent() && root.get().isLocal()) || hasLocalClassAssertions();
    }

    protected boolean hasLocalClassAssertions() {
        return Iterators.findFirst(listClassAssertions().filterKeep(OntStatement::isLocal)).isPresent();
    }

    /**
     * Lists all class assertion statements.
     *
     * @return {@link ExtendedIterator} over all class assertions.
     */
    public ExtendedIterator listClassAssertions() {
        return listStatements(RDF.type).filterKeep(s -> s.getObject().canAs(OntClass.class));
    }

    @SuppressWarnings("rawtypes")
    @Override
    public Stream negativeAssertions() {
        return Iterators.asStream(listNegativeAssertions(), getCharacteristics());
    }

    @SuppressWarnings("rawtypes")
    public ExtendedIterator listNegativeAssertions() {
        return listSubjects(OWL2.sourceIndividual, OntNegativeAssertion.class);
    }

    @Override
    protected Set getContent() {
        Set res = super.getContent();
        listNegativeAssertions().forEachRemaining(x -> res.addAll(((OntObjectImpl) x).getContent()));
        return res;
    }

    /**
     * Represents a named individual.
     * Note: it may not have {@link OntObject#getMainStatement()} statement.
     */
    public static class NamedImpl extends OntIndividualImpl implements Named {
        public NamedImpl(Node n, EnhGraph m) {
            super(checkNamed(n), m);
        }

        @Override
        public Optional findRootStatement() {
            return Optional.of(getModel().createStatement(this, RDF.type, OWL2.NamedIndividual).asRootStatement())
                    .filter(r -> getModel().contains(r));
        }

        @Override
        public boolean isBuiltIn() {
            return false;
        }

        @Override
        public Class objectType() {
            return Named.class;
        }

        @Override
        public NamedImpl detachClass(Resource clazz) {
            OntGraphModelImpl m = getModel();
            m.listOntStatements(this, RDF.type, clazz)
                    .filterDrop(s -> OWL2.NamedIndividual.equals(s.getObject()))
                    .toList()
                    .forEach(s -> m.remove(s.clearAnnotations()));
            return this;
        }
    }

    /**
     * See description to the interface {@link Anonymous}.
     * The current implementation allows treating b-node as anonymous individual
     * in any case except the following cases:
     * 
    *
  • it is a subject in statement "_:x rdf:type s", where "s" is not a class expression ("C").
  • *
  • it is a subject in statement "_:x @predicate @any", where @predicate is from reserved vocabulary * but not object, data or annotation built-in property * and not owl:sameAs and owl:differentFrom.
  • *
  • it is an object in statement "@any @predicate _:x", where @predicate is from reserved vocabulary * but not object, data or annotation built-in property * and not owl:sameAs, owl:differentFrom, owl:hasValue, owl:sourceIndividual and rdf:first.
  • *
*

* for notations see OWL2 Quick Refs */ @SuppressWarnings("javadoc") public static class AnonymousImpl extends OntIndividualImpl implements Anonymous { public AnonymousImpl(Node n, EnhGraph m) { super(n, m); } @Override public boolean isLocal() { return hasLocalClassAssertions(); } @Override public Optional findRootStatement() { return Optional.empty(); } @Override public Class objectType() { return Anonymous.class; } @Override public AnonymousImpl detachClass(Resource clazz) { Set classes = classes().collect(Collectors.toSet()); if (clazz == null && !classes.isEmpty()) { throw new OntJenaException.IllegalState("Detaching classes is prohibited: " + "the anonymous individual (" + this + ") should contain at least one class assertion, " + "otherwise it can be lost"); } if (classes.size() == 1 && classes.iterator().next().equals(clazz)) { throw new OntJenaException.IllegalState("Detaching class (" + clazz + ") is prohibited: " + "it is a single class assertion for the individual " + this + "."); } remove(RDF.type, clazz); return this; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy