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

org.obolibrary.obo2owl.OboInOwlCardinalityTools Maven / Gradle / Ivy

There is a newer version: 5.5.1
Show newest version
package org.obolibrary.obo2owl;

import static org.semanticweb.owlapi.model.parameters.Imports.INCLUDED;

import java.util.*;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.obolibrary.oboformat.model.Frame;
import org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag;
import org.semanticweb.owlapi.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Tools for checking and fixing cardinality constrains for OBO ontologies in
 * OWL.
 */
public final class OboInOwlCardinalityTools {

    protected static final Logger LOGGER = LoggerFactory.getLogger(OboInOwlCardinalityTools.class);

    private OboInOwlCardinalityTools() {}

    /**
     * Functor for resolving conflicts for an annotation property and its
     * cardinality constraint.
     */
    public interface AnnotationCardinalityConfictHandler {

        /**
         * Resolve a conflict for a given annotation property and axioms. The
         * result is either a list of resolved axioms or an exception thrown by
         * this method.
         * 
         * @param entity
         *        entity
         * @param property
         *        property
         * @param axioms
         *        axioms
         * @return list of resolved axioms
         * @throws AnnotationCardinalityException
         *         AnnotationCardinalityException
         */
        @Nonnull
        List handleConflict(@Nonnull OWLEntity entity,
            @Nonnull OWLAnnotationProperty property, @Nonnull Collection axioms)
                throws AnnotationCardinalityException;

        /**
         * Resolve a conflict for a given annotation property and ontology
         * annotations. The result is either a list of resolved annotations or
         * an exception thrown by this method.
         * 
         * @param property
         *        property
         * @param ontologyAnnotations
         *        ontologyAnnotations
         * @return list of resolved annotations
         * @throws AnnotationCardinalityException
         *         AnnotationCardinalityException
         */
        @Nonnull
        List handleConflict(@Nonnull OWLAnnotationProperty property,
            @Nonnull Collection ontologyAnnotations) throws AnnotationCardinalityException;
    }

    /**
     * Functor for reporting conflicts for an annotation property and its
     * cardinality constraint.
     */
    public interface AnnotationCardinalityReporter {

        /**
         * Report a conflict for a given annotation property and axioms.
         * 
         * @param entity
         *        entity
         * @param property
         *        property
         * @param axioms
         *        axioms
         */
        void reportConflict(@Nonnull OWLEntity entity, @Nonnull OWLAnnotationProperty property,
            @Nonnull Collection axioms);

        /**
         * Report a conflict for a given annotation property and ontology
         * annotations.
         * 
         * @param property
         *        property
         * @param ontologyAnnotations
         *        ontologyAnnotations
         */
        void reportConflict(@Nonnull OWLAnnotationProperty property,
            @Nonnull Collection ontologyAnnotations);
    }

    /**
     * Exception indication a non-resolvable conflict for an annotation property
     * and its cardinality constraint.
     */
    public static class AnnotationCardinalityException extends Exception {

        // generated
        private static final long serialVersionUID = 40000L;

        /**
         * Create a new Exception.
         * 
         * @param message
         *        message
         * @param cause
         *        cause
         */
        public AnnotationCardinalityException(@Nonnull String message, @Nonnull Throwable cause) {
            super(message, cause);
        }

        /**
         * Create a new Exception.
         * 
         * @param message
         *        message
         */
        public AnnotationCardinalityException(@Nonnull String message) {
            super(message);
        }
    }

    /**
     * Check the annotations for cardinality violations. Try to resolve
     * conflicts with the given handler.
     * 
     * @param ontology
     *        the target ontology
     * @param reporter
     *        reporter
     * @param handler
     *        the conflict handler
     * @throws AnnotationCardinalityException
     *         throws exception in case a conflict cannot be resolved by the
     *         handler
     * @see Frame#check() for implementation in OBO
     */
    public static void checkAnnotationCardinality(@Nonnull OWLOntology ontology,
        @Nullable AnnotationCardinalityReporter reporter, @Nullable AnnotationCardinalityConfictHandler handler)
            throws AnnotationCardinalityException {
        OWLOntologyManager manager = ontology.getOWLOntologyManager();
        OWLDataFactory factory = manager.getOWLDataFactory();
        Set headerProperties = getProperties(factory, OboFormatTag.TAG_ONTOLOGY,
            OboFormatTag.TAG_FORMAT_VERSION, OboFormatTag.TAG_DATE, OboFormatTag.TAG_DEFAULT_NAMESPACE,
            OboFormatTag.TAG_SAVED_BY, OboFormatTag.TAG_AUTO_GENERATED_BY);
        checkOntologyAnnotations(headerProperties, ontology, reporter, handler, manager);
        Set properties = getProperties(factory, OboFormatTag.TAG_IS_ANONYMOUS,
            OboFormatTag.TAG_NAME, OboFormatTag.TAG_NAMESPACE, OboFormatTag.TAG_DEF, OboFormatTag.TAG_COMMENT,
            OboFormatTag.TAG_DOMAIN, OboFormatTag.TAG_RANGE, OboFormatTag.TAG_IS_ANTI_SYMMETRIC,
            OboFormatTag.TAG_IS_CYCLIC, OboFormatTag.TAG_IS_REFLEXIVE, OboFormatTag.TAG_IS_SYMMETRIC,
            OboFormatTag.TAG_IS_TRANSITIVE, OboFormatTag.TAG_IS_FUNCTIONAL, OboFormatTag.TAG_IS_INVERSE_FUNCTIONAL,
            OboFormatTag.TAG_IS_OBSELETE, OboFormatTag.TAG_CREATED_BY, OboFormatTag.TAG_CREATION_DATE);
        for (OWLClass owlClass : ontology.getClassesInSignature(INCLUDED)) {
            assert owlClass != null;
            checkOwlEntity(owlClass, properties, ontology, reporter, handler, manager);
        }
        for (OWLObjectProperty owlProperty : ontology.getObjectPropertiesInSignature(INCLUDED)) {
            assert owlProperty != null;
            checkOwlEntity(owlProperty, properties, ontology, reporter, handler, manager);
        }
    }

    @Nonnull
    private static Set getProperties(@Nonnull OWLDataFactory factory,
        @Nonnull OboFormatTag... tags) {
        Set set = new HashSet<>();
        for (OboFormatTag tag : tags) {
            IRI iri = OWLAPIObo2Owl.trTagToIRI(tag.getTag());
            OWLAnnotationProperty property = factory.getOWLAnnotationProperty(iri);
            set.add(property);
        }
        return set;
    }

    private static void checkOntologyAnnotations(@Nonnull Set properties,
        @Nonnull OWLOntology ontology, @Nullable AnnotationCardinalityReporter reporter,
        @Nullable AnnotationCardinalityConfictHandler handler, @Nonnull OWLOntologyManager manager)
            throws AnnotationCardinalityException {
        Set annotations = ontology.getAnnotations();
        Map> groupedAnnotations = new HashMap<>();
        for (OWLAnnotation annotation : annotations) {
            OWLAnnotationProperty current = annotation.getProperty();
            if (properties.contains(current)) {
                Set set = groupedAnnotations.get(current);
                if (set == null) {
                    groupedAnnotations.put(current, Collections.singleton(annotation));
                } else if (set.size() == 1) {
                    set = new HashSet<>(set);
                    set.add(annotation);
                    groupedAnnotations.put(current, set);
                } else {
                    set.add(annotation);
                }
            }
        }
        // check cardinality constraint
        for (OWLAnnotationProperty property : groupedAnnotations.keySet()) {
            assert property != null;
            Set group = groupedAnnotations.get(property);
            if (group.size() > 1) {
                if (reporter != null) {
                    // report conflict
                    reporter.reportConflict(property, group);
                }
                if (handler != null) {
                    // handle conflict
                    // if conflict is not resolvable, throws exception
                    List changed = handler.handleConflict(property, group);
                    for (OWLAnnotation annotation : group) {
                        assert annotation != null;
                        manager.applyChange(new RemoveOntologyAnnotation(ontology, annotation));
                    }
                    for (OWLAnnotation annotation : changed) {
                        assert annotation != null;
                        manager.applyChange(new AddOntologyAnnotation(ontology, annotation));
                    }
                }
            }
        }
    }

    private static void checkOwlEntity(@Nonnull OWLEntity owlClass, @Nonnull Set properties,
        @Nonnull OWLOntology ontology, @Nullable AnnotationCardinalityReporter reporter,
        @Nullable AnnotationCardinalityConfictHandler handler, @Nonnull OWLOntologyManager manager)
            throws AnnotationCardinalityException {
        Set axioms = ontology.getAnnotationAssertionAxioms(owlClass.getIRI());
        Map> groupedAxioms = new HashMap<>();
        for (OWLAnnotationAssertionAxiom axiom : axioms) {
            OWLAnnotationProperty current = axiom.getProperty();
            if (properties.contains(current)) {
                Set set = groupedAxioms.get(current);
                if (set == null) {
                    groupedAxioms.put(current, Collections.singleton(axiom));
                } else if (set.size() == 1) {
                    set = new HashSet<>(set);
                    set.add(axiom);
                    groupedAxioms.put(current, set);
                } else {
                    set.add(axiom);
                }
            }
        }
        // check cardinality constraint
        for (OWLAnnotationProperty property : groupedAxioms.keySet()) {
            assert property != null;
            Set group = groupedAxioms.get(property);
            if (group.size() > 1) {
                if (reporter != null) {
                    // report conflict
                    reporter.reportConflict(owlClass, property, group);
                }
                if (handler != null) {
                    // handle conflict
                    // if conflict is not resolvable, throws exception
                    List changed = handler.handleConflict(owlClass, property, group);
                    for (OWLAnnotationAssertionAxiom axiom : group) {
                        assert axiom != null;
                        manager.removeAxiom(ontology, axiom);
                    }
                    for (OWLAnnotationAssertionAxiom axiom : changed) {
                        assert axiom != null;
                        manager.addAxiom(ontology, axiom);
                    }
                }
            }
        }
    }

    /**
     * Check the annotations for cardinality violations. Try to resolve
     * conflicts with the default handler.
     * 
     * @param ontology
     *        the target ontology
     * @throws AnnotationCardinalityException
     *         throws exception in case a conflict cannot be resolved by the
     *         handler
     * @see #DEFAULT_HANDLER
     */
    public static void checkAnnotationCardinality(@Nonnull OWLOntology ontology) throws AnnotationCardinalityException {
        checkAnnotationCardinality(ontology, null, DEFAULT_HANDLER);
    }

    /**
     * Check the annotations for cardinality violations. Only report violations
     * via the given reporter
     * 
     * @param ontology
     *        the target ontology
     * @param reporter
     *        used to report violations
     */
    public static void checkAnnotationCardinality(@Nonnull OWLOntology ontology,
        AnnotationCardinalityReporter reporter) {
        try {
            checkAnnotationCardinality(ontology, reporter, null);
        } catch (AnnotationCardinalityException e) {
            // this will not happen as no handler is registered
            LOGGER.error("Cardinality exception during report: This isn't supposed to happen.", e);
        }
    }

    /** default handler */
    @Nonnull
    public static final AnnotationCardinalityConfictHandler DEFAULT_HANDLER = new AnnotationCardinalityConfictHandler() {

        @Nonnull
        @Override
        public List handleConflict(@Nonnull OWLEntity entity,
            @Nonnull OWLAnnotationProperty property, @Nonnull Collection axioms)
                throws AnnotationCardinalityException {
            if (axioms.size() > 1) {
                String tag = OWLAPIOwl2Obo.owlObjectToTag(property);
                if (tag == null) {
                    tag = property.getIRI().toString();
                }
                // take the first one in the collection
                // (may be random)
                LOGGER.info("Fixing multiple {} tags for entity: {}", tag, entity.getIRI());
                return listOfFirst(axioms);
            }
            throw new AnnotationCardinalityException("Could not resolve conflict for property: " + property);
        }

        @Nonnull
        @Override
        public List handleConflict(@Nonnull OWLAnnotationProperty property,
            @Nonnull Collection ontologyAnnotations) throws AnnotationCardinalityException {
            if (ontologyAnnotations.size() > 1) {
                String tag = OWLAPIOwl2Obo.owlObjectToTag(property);
                if (tag == null) {
                    tag = property.getIRI().toString();
                }
                // take the first one in the collection
                // (may be random)
                LOGGER.info("Fixing multiple ontolgy annotations with, tag: {}", tag);
                return listOfFirst(ontologyAnnotations);
            }
            throw new AnnotationCardinalityException("Could not resolve conflict for property: " + property);
        }
    };

    @Nonnull
    static  List listOfFirst(Collection t) {
        return Collections.singletonList(t.iterator().next());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy