org.protege.editor.owl.model.hierarchy.AbstractOWLPropertyHierarchyProvider Maven / Gradle / Ivy
package org.protege.editor.owl.model.hierarchy;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.search.EntitySearcher;
import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
/**
* Author: Matthew Horridge
* The University Of Manchester
* Bio-Health Informatics Group
* Date: 23-Jan-2007
*/
public abstract class AbstractOWLPropertyHierarchyProvider extends AbstractOWLObjectHierarchyProvider {
// private static final Logger logger = LoggerFactory.getLogger(AbstractOWLPropertyHierarchyProvider.class);
private ReadLock ontologySetReadLock;
private WriteLock ontologySetWriteLock;
/*
* The ontologies variable is protected by the ontologySetReadLock and the ontologySetWriteLock.
* These locks are always taken and held inside of the getReadLock() and getWriteLock()'s for the
* OWL Ontology Manager. This is necessary because when the set of ontologies changes, everything
* about this class changes. So when the set of ontologies is changed we need to make sure that nothing
* else is running.
*/
private Set ontologies;
private Set subPropertiesOfRoot;
private OWLOntologyChangeListener listener;
public AbstractOWLPropertyHierarchyProvider(OWLOntologyManager owlOntologyManager) {
super(owlOntologyManager);
this.subPropertiesOfRoot = new HashSet<>();
ontologies = new FakeSet<>();
ReentrantReadWriteLock locks = new ReentrantReadWriteLock();
ontologySetReadLock = locks.readLock();
ontologySetWriteLock = locks.writeLock();
listener = this::handleChanges;
owlOntologyManager.addOntologyChangeListener(listener);
}
public void dispose() {
super.dispose();
getManager().removeOntologyChangeListener(listener);
}
/*
* This call holds the write lock so no other thread can hold the either the OWL ontology
* manager read or write locks or the ontologies
*/
private void handleChanges(List changes) {
Set
properties = new HashSet<>(getPropertiesReferencedInChange(changes));
for (P prop : properties) {
if (isSubPropertyOfRoot(prop)) {
subPropertiesOfRoot.add(prop);
fireNodeChanged(getRoot());
}
else {
if (getAncestors(prop).contains(prop)) {
subPropertiesOfRoot.add(prop);
getAncestors(prop).stream()
.filter(anc -> getAncestors(anc).contains(prop))
.forEach(anc -> {
subPropertiesOfRoot.add(anc);
fireNodeChanged(anc);
});
}
else {
subPropertiesOfRoot.remove(prop);
}
}
fireNodeChanged(prop);
}
fireNodeChanged(getRoot());
}
protected abstract Set
getPropertiesReferencedInChange(List changes);
private boolean isSubPropertyOfRoot(P prop) {
if (prop.equals(getRoot())) {
return false;
}
// We deem a property to be a sub of the top property if this is asserted
// or if no named superproperties are asserted
final Set
parents = getParents(prop);
if (parents.isEmpty() || parents.contains(getRoot())) {
for (OWLOntology ont : ontologies) {
if (containsReference(ont, prop)) {
return true;
}
}
}
// Additional condition: If we have P -> Q and Q -> P, then
// there is no path to the root, so put P and Q as root properties
// Collapse any cycles and force properties that are equivalent
// through cycles to appear at the root.
return getAncestors(prop).contains(prop);
}
private void rebuildRoots() {
subPropertiesOfRoot.clear();
for (OWLOntology ontology : ontologies) {
for (P prop : getReferencedProperties(ontology)) {
if (isSubPropertyOfRoot(prop)) {
subPropertiesOfRoot.add(prop);
}
}
}
}
protected abstract boolean containsReference(OWLOntology ont, P prop);
/**
* Gets the relevant properties in the specified ontology that are contained
* within the property hierarchy. For example, for an object property hierarchy
* this would constitute the set of referenced object properties in the specified
* ontology.
*
* @param ont The ontology
*/
protected abstract Set getReferencedProperties(OWLOntology ont);
protected abstract Set getSubPropertyAxiomForRHS(P prop, OWLOntology ont);
protected abstract P getRoot();
/**
* Gets the objects that represent the roots of the hierarchy.
*/
public Set
getRoots() {
return Collections.singleton(getRoot());
}
/**
* Sets the ontologies that this hierarchy provider should use
* in order to determine the hierarchy.
*/
final public void setOntologies(Set ontologies) {
// getReadLock().lock();
ontologySetWriteLock.lock();
try {
this.ontologies.clear();
this.ontologies.addAll(ontologies);
rebuildRoots();
fireHierarchyChanged();
} finally {
ontologySetWriteLock.unlock();
// getReadLock().unlock();
}
}
public boolean containsReference(P object) {
// getReadLock().lock();
ontologySetReadLock.lock();
try {
for (OWLOntology ont : ontologies) {
if (getReferencedProperties(ont).contains(object)) {
return true;
}
}
return false;
} finally {
ontologySetReadLock.unlock();
// getReadLock().unlock();
}
}
public Set getUnfilteredChildren(P object) {
// getReadLock().lock();
ontologySetReadLock.lock();
try {
if (object.equals(getRoot())) {
return Collections.unmodifiableSet(subPropertiesOfRoot);
}
final Set
result = new HashSet<>();
for (E subProp : getSubProperties(object, ontologies)) {
// Don't add the sub property if it is a parent of
// itself - i.e. prevent cycles
if (!subProp.isAnonymous() &&
!getAncestors((P) subProp).contains(subProp)) {
result.add((P) subProp);
}
}
return result;
} finally {
ontologySetReadLock.unlock();
// getReadLock().unlock();
}
}
protected abstract Collection
getSubProperties(P object, Set ontologies);
public Set getEquivalents(P object) {
// getReadLock().lock();
ontologySetReadLock.lock();
try {
Set
result = new HashSet<>();
Set
ancestors = getAncestors(object);
if (ancestors.contains(object)) {
for (P anc : ancestors) {
if (getAncestors(anc).contains(object)) {
result.add(anc);
}
}
}
for (E prop : EntitySearcher.getEquivalentProperties(object, ontologies)) {
if (!prop.isAnonymous()) {
result.add((P) prop);
}
}
result.remove(object);
return result;
} finally {
ontologySetReadLock.unlock();
// getReadLock().unlock();
}
}
public Set
getParents(P object) {
// getReadLock().lock();
ontologySetReadLock.lock();
try {
if (object.equals(getRoot())) {
return Collections.emptySet();
}
Set
result = new HashSet<>();
for (E prop : getSuperProperties(object, ontologies)) {
if (!prop.isAnonymous()) {
result.add((P) prop);
}
}
if (result.isEmpty() && isReferenced(object)) {
result.add(getRoot());
}
return result;
} finally {
ontologySetReadLock.unlock();
// getReadLock().unlock();
}
}
protected abstract Collection
getSuperProperties(P subProperty, Set ontologies);
private boolean isReferenced(P e) {
return e.accept(new IsReferencePropertyExpressionVisitor());
}
private class IsReferencePropertyExpressionVisitor implements OWLPropertyExpressionVisitorEx {
@Override
public Boolean visit(OWLAnnotationProperty owlAnnotationProperty) {
return isReferenced(owlAnnotationProperty);
}
public Boolean visit(OWLObjectProperty property) {
return isReferenced(property);
}
public Boolean visit(OWLObjectInverseOf property) {
return property.getInverse().accept(this);
}
public Boolean visit(OWLDataProperty property) {
return isReferenced(property);
}
private boolean isReferenced(OWLEntity e) {
for (OWLOntology ontology : ontologies) {
if (ontology.containsEntityInSignature(e)) {
return true;
}
}
return false;
}
}
private class FakeSet extends AbstractSet {
private List elements = new ArrayList<>();
@Override
public Iterator iterator() {
return elements.iterator();
}
@Override
public int size() {
return elements.size();
}
@Override
public boolean add(X e) {
if (!elements.contains(e)) {
elements.add(e);
return true;
}
return false;
}
@Override
public void clear() {
elements.clear();
}
}
}