org.obolibrary.obo2owl.OboInOwlCardinalityTools Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of owlapi-oboformat Show documentation
Show all versions of owlapi-oboformat Show documentation
A java library for converting obo format documents to OWL, and for converting (a subset of) OWL to obo format. This version has been slightly modified to be included directly in the OWL API.
The upstream code for this module and its authors can be found at https://code.google.com/p/oboformat/.
package org.obolibrary.obo2owl;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_AUTO_GENERATED_BY;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_COMMENT;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_CREATED_BY;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_CREATION_DATE;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_DATE;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_DEF;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_DEFAULT_NAMESPACE;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_DOMAIN;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_FORMAT_VERSION;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_IS_ANONYMOUS;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_IS_ANTI_SYMMETRIC;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_IS_CYCLIC;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_IS_FUNCTIONAL;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_IS_INVERSE_FUNCTIONAL;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_IS_OBSELETE;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_IS_REFLEXIVE;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_IS_SYMMETRIC;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_IS_TRANSITIVE;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_NAME;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_NAMESPACE;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_ONTOLOGY;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_RANGE;
import static org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag.TAG_SAVED_BY;
import static org.semanticweb.owlapi.model.parameters.Imports.INCLUDED;
import static org.semanticweb.owlapi.util.OWLAPIStreamUtils.asUnorderedSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import org.obolibrary.oboformat.model.Frame;
import org.obolibrary.oboformat.parser.OBOFormatConstants.OboFormatTag;
import org.semanticweb.owlapi.model.AddOntologyAnnotation;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAnnotationAssertionAxiom;
import org.semanticweb.owlapi.model.OWLAnnotationProperty;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLRuntimeException;
import org.semanticweb.owlapi.model.RemoveOntologyAnnotation;
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);
/**
* Default handler.
*/
public static final AnnotationCardinalityConfictHandler DEFAULT_HANDLER = new AnnotationCardinalityConfictHandler() {
@Override
public List handleConflict(OWLEntity entity,
OWLAnnotationProperty property,
Collection axioms) {
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);
}
@Override
public List handleConflict(OWLAnnotationProperty property,
Collection ontologyAnnotations) {
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);
}
};
private OboInOwlCardinalityTools() {
}
/**
* 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(OWLOntology ontology,
@Nullable AnnotationCardinalityReporter reporter,
@Nullable AnnotationCardinalityConfictHandler handler) {
OWLOntologyManager manager = ontology.getOWLOntologyManager();
OWLDataFactory factory = manager.getOWLDataFactory();
Set headerProperties = getProperties(factory, TAG_ONTOLOGY,
TAG_FORMAT_VERSION, TAG_DATE,
TAG_DEFAULT_NAMESPACE, TAG_SAVED_BY, TAG_AUTO_GENERATED_BY);
checkOntologyAnnotations(headerProperties, ontology, reporter, handler, manager);
Set properties = getProperties(factory, TAG_IS_ANONYMOUS, TAG_NAME,
TAG_NAMESPACE,
TAG_DEF, TAG_COMMENT, TAG_DOMAIN, TAG_RANGE, TAG_IS_ANTI_SYMMETRIC, TAG_IS_CYCLIC,
TAG_IS_REFLEXIVE,
TAG_IS_SYMMETRIC, TAG_IS_TRANSITIVE, TAG_IS_FUNCTIONAL, TAG_IS_INVERSE_FUNCTIONAL,
TAG_IS_OBSELETE,
TAG_CREATED_BY, TAG_CREATION_DATE);
ontology.classesInSignature(INCLUDED)
.forEach(c -> checkOwlEntity(c, properties, ontology, reporter, handler));
ontology.objectPropertiesInSignature(INCLUDED)
.forEach(p -> checkOwlEntity(p, properties, ontology, reporter,
handler));
}
private static Set getProperties(OWLDataFactory factory,
OboFormatTag... tags) {
Set set = new HashSet<>();
for (OboFormatTag tag : tags) {
set.add(factory.getOWLAnnotationProperty(OWLAPIObo2Owl.trTagToIRI(tag.getTag())));
}
return set;
}
private static void checkOntologyAnnotations(Set properties,
OWLOntology ontology,
@Nullable AnnotationCardinalityReporter reporter,
@Nullable AnnotationCardinalityConfictHandler handler,
OWLOntologyManager manager) {
Set annotations = asUnorderedSet(ontology.annotations());
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 (Map.Entry> e : groupedAnnotations
.entrySet()) {
if (e.getValue().size() > 1) {
if (reporter != null) {
// report conflict
reporter.reportConflict(e.getKey(), e.getValue());
}
if (handler != null) {
// handle conflict
// if conflict is not resolvable, throws exception
List changed = handler.handleConflict(e.getKey(), e.getValue());
e.getValue().forEach(
a -> manager.applyChange(new RemoveOntologyAnnotation(ontology, a)));
changed
.forEach(a -> manager.applyChange(new AddOntologyAnnotation(ontology, a)));
}
}
}
}
private static void checkOwlEntity(OWLEntity owlClass, Set properties,
OWLOntology ontology,
@Nullable AnnotationCardinalityReporter reporter,
@Nullable AnnotationCardinalityConfictHandler handler) {
Map> groupedAxioms = new HashMap<>();
for (OWLAnnotationAssertionAxiom axiom : asUnorderedSet(
ontology.annotationAssertionAxioms(owlClass
.getIRI()))) {
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 (Map.Entry> e : groupedAxioms
.entrySet()) {
if (e.getValue().size() > 1) {
if (reporter != null) {
// report conflict
reporter.reportConflict(owlClass, e.getKey(), e.getValue());
}
if (handler != null) {
// handle conflict
// if conflict is not resolvable, throws exception
List changed = handler
.handleConflict(owlClass, e.getKey(), e
.getValue());
ontology.remove(e.getValue());
ontology.add(changed);
}
}
}
}
/**
* 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(OWLOntology ontology) {
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(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);
}
}
static List listOfFirst(Collection t) {
return Collections.singletonList(t.iterator().next());
}
/**
* 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
*/
List handleConflict(OWLEntity entity,
OWLAnnotationProperty property,
Collection axioms);
/**
* 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
*/
List handleConflict(OWLAnnotationProperty property,
Collection ontologyAnnotations);
}
/**
* 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(OWLEntity entity, OWLAnnotationProperty property,
Collection axioms);
/**
* Report a conflict for a given annotation property and ontology
* annotations.
*
* @param property property
* @param ontologyAnnotations ontologyAnnotations
*/
void reportConflict(OWLAnnotationProperty property,
Collection ontologyAnnotations);
}
/**
* Exception indication a non-resolvable conflict for an annotation property
* and its cardinality constraint.
*/
public static class AnnotationCardinalityException extends OWLRuntimeException {
/**
* Create a new Exception.
*
* @param message message
* @param cause cause
*/
public AnnotationCardinalityException(String message, Throwable cause) {
super(message, cause);
}
/**
* Create a new Exception.
*
* @param message message
*/
public AnnotationCardinalityException(String message) {
super(message);
}
}
}