![JAR search and dependency download from the Maven repository](/logo.png)
edu.stanford.protege.webprotege.hierarchy.ClassHierarchyProviderImpl Maven / Gradle / Ivy
The newest version!
package edu.stanford.protege.webprotege.hierarchy;
import com.google.common.base.Stopwatch;
import edu.stanford.protege.webprotege.change.OntologyChange;
import edu.stanford.protege.webprotege.index.*;
import edu.stanford.protege.webprotege.inject.ProjectSingleton;
import edu.stanford.protege.webprotege.common.ProjectId;
import org.protege.owlapi.inference.orphan.TerminalElementFinder;
import org.semanticweb.owlapi.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.util.*;
import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
/**
* Author: Matthew Horridge
* The University Of Manchester
* Bio-Health Informatics Group
* Date: 17-Jan-2007
*/
@ProjectSingleton
public class ClassHierarchyProviderImpl extends AbstractHierarchyProvider implements ClassHierarchyProvider {
private static final Logger logger = LoggerFactory.getLogger(ClassHierarchyProviderImpl.class);
@Nonnull
private final ProjectId projectId;
@Nonnull
private final OWLClass root;
@Nonnull
private final TerminalElementFinder rootFinder;
@Nonnull
private final Set nodesToUpdate = new HashSet<>();
@Nonnull
private final ProjectOntologiesIndex projectOntologiesIndex;
@Nonnull
private final SubClassOfAxiomsBySubClassIndex subClassOfAxiomsIndex;
@Nonnull
private final EquivalentClassesAxiomsIndex equivalentClassesAxiomsIndex;
@Nonnull
private final ProjectSignatureByTypeIndex projectSignatureByTypeIndex;
@Nonnull
private final EntitiesInProjectSignatureByIriIndex entitiesInProjectSignatureByIriIndex;
@Nonnull
private final ClassHierarchyChildrenAxiomsIndex classHierarchyChildrenAxiomsIndex;
private boolean stale = true;
@Inject
public ClassHierarchyProviderImpl(ProjectId projectId,
@Nonnull @ClassHierarchyRoot OWLClass rootCls,
@Nonnull ProjectOntologiesIndex projectOntologiesIndex,
@Nonnull SubClassOfAxiomsBySubClassIndex subClassOfAxiomsIndex,
@Nonnull EquivalentClassesAxiomsIndex equivalentClassesAxiomsIndex,
@Nonnull ProjectSignatureByTypeIndex projectSignatureByTypeIndex,
@Nonnull EntitiesInProjectSignatureByIriIndex entitiesInProjectSignatureByIriIndex,
@Nonnull ClassHierarchyChildrenAxiomsIndex classHierarchyChildrenAxiomsIndex) {
this.projectId = checkNotNull(projectId);
this.root = checkNotNull(rootCls);
this.projectOntologiesIndex = projectOntologiesIndex;
this.subClassOfAxiomsIndex = subClassOfAxiomsIndex;
this.equivalentClassesAxiomsIndex = equivalentClassesAxiomsIndex;
this.projectSignatureByTypeIndex = projectSignatureByTypeIndex;
this.entitiesInProjectSignatureByIriIndex = entitiesInProjectSignatureByIriIndex;
this.classHierarchyChildrenAxiomsIndex = classHierarchyChildrenAxiomsIndex;
rootFinder = new TerminalElementFinder<>(this::getParents);
nodesToUpdate.clear();
}
public synchronized Collection getParents(OWLClass object) {
rebuildIfNecessary();
// If the object is thing then there are no
// parents
if(object.equals(root)) {
return Collections.emptySet();
}
Stream parentsCombined = getParentsStream(object);
var parents = parentsCombined.collect(toSet());
// Thing if the object is a root class
if(rootFinder.getTerminalElements()
.contains(object)) {
parents.add(root);
}
return parents;
}
@Override
public boolean isParent(OWLClass child, OWLClass parent) {
return getParentsStream(child).anyMatch(c -> c.equals(parent));
}
private Stream getParentsStream(OWLClass object) {
var subClassOfAxiomsParents =
projectOntologiesIndex.getOntologyIds()
.flatMap(ontId -> subClassOfAxiomsIndex.getSubClassOfAxiomsForSubClass(object,
ontId))
.map(OWLSubClassOfAxiom::getSuperClass)
.flatMap(this::asConjunctSet)
.filter(OWLClassExpression::isNamed)
.map(OWLClassExpression::asOWLClass);
var equivalentClassesAxiomsParents =
projectOntologiesIndex.getOntologyIds()
.flatMap(ontId -> equivalentClassesAxiomsIndex.getEquivalentClassesAxioms(
object,
ontId))
.flatMap(ax -> ax.getClassExpressions()
.stream())
.filter(ce -> !ce.equals(object))
.flatMap(this::asConjunctSet)
.filter(OWLClassExpression::isNamed)
.map(OWLClassExpression::asOWLClass);
return Stream.concat(subClassOfAxiomsParents, equivalentClassesAxiomsParents);
}
private void rebuildIfNecessary() {
if(stale) {
rebuildImplicitRoots();
}
}
private Stream asConjunctSet(@Nonnull OWLClassExpression cls) {
if(cls instanceof OWLObjectIntersectionOf) {
return ((OWLObjectIntersectionOf) cls).getOperandsAsList()
.stream()
.flatMap(this::asConjunctSet);
}
else {
return Stream.of(cls);
}
}
private void rebuildImplicitRoots() {
stale = false;
Stopwatch stopwatch = Stopwatch.createStarted();
logger.info("{} Rebuilding class hierarchy", projectId);
rootFinder.clear();
var signature = projectSignatureByTypeIndex.getSignature(EntityType.CLASS)
.collect(toImmutableSet());
rootFinder.appendTerminalElements(signature);
rootFinder.finish();
logger.info("{} Rebuilt class hierarchy in {} ms", projectId, stopwatch.elapsed(MILLISECONDS));
}
public void dispose() {
}
public synchronized void handleChanges(@Nonnull List changes) {
Set oldTerminalElements = new HashSet<>(rootFinder.getTerminalElements());
Set changedClasses = new HashSet<>();
changedClasses.add(root);
var filteredChanges = filterIrrelevantChanges(changes);
updateImplicitRoots(filteredChanges);
for(OntologyChange change : filteredChanges) {
changedClasses.addAll(change.getSignature()
.stream()
.filter(OWLEntity::isOWLClass)
.filter(entity -> !entity.equals(root))
.map(entity -> (OWLClass) entity)
.collect(toList()));
}
changedClasses.forEach(this::registerNodeChanged);
rootFinder.getTerminalElements()
.stream()
.filter(cls -> !oldTerminalElements.contains(cls))
.forEach(this::registerNodeChanged);
oldTerminalElements.stream()
.filter(cls -> !rootFinder.getTerminalElements()
.contains(cls))
.forEach(this::registerNodeChanged);
notifyNodeChanges();
}
private List filterIrrelevantChanges(List changes) {
return changes.stream()
.filter(OntologyChange::isAxiomChange)
.collect(toList());
}
private void updateImplicitRoots(List changes) {
Set possibleTerminalElements = new HashSet<>();
Set notInOntologies = new HashSet<>();
// only listen for changes on the appropriate ontologies
changes.stream()
.filter(OntologyChange::isAxiomChange)
.forEach(change -> {
boolean remove = change.isRemoveAxiom();
var axiom = change.getAxiomOrThrow();
axiom.getSignature()
.stream()
.filter(OWLEntity::isOWLClass)
.filter(entity -> !entity.equals(root))
.forEach(entity -> {
OWLClass cls = (OWLClass) entity;
if(!remove || containsReference(cls)) {
possibleTerminalElements.add(cls);
}
else {
notInOntologies.add(cls);
}
});
});
possibleTerminalElements.addAll(rootFinder.getTerminalElements());
possibleTerminalElements.removeAll(notInOntologies);
rootFinder.findTerminalElements(possibleTerminalElements);
}
private void registerNodeChanged(OWLClass node) {
nodesToUpdate.add(node);
}
private void notifyNodeChanges() {
nodesToUpdate.clear();
}
public synchronized boolean containsReference(OWLClass object) {
return entitiesInProjectSignatureByIriIndex
.getEntitiesInSignature(object.getIRI())
.anyMatch(entity -> entity.equals(object));
}
public synchronized Collection getRoots() {
rebuildIfNecessary();
return Collections.singleton(root);
}
public synchronized Collection getChildren(OWLClass object) {
rebuildIfNecessary();
Set result;
if(object.equals(root)) {
result = new HashSet<>();
result.addAll(rootFinder.getTerminalElements());
result.addAll(extractChildren(object));
result.remove(object);
}
else {
result = extractChildren(object);
// result.removeIf(curChild -> getAncestors(object).contains(curChild));
}
return result;
}
private Set extractChildren(OWLClass parent) {
return classHierarchyChildrenAxiomsIndex.getChildrenAxioms(parent)
.flatMap(ax -> {
if(ax instanceof OWLSubClassOfAxiom) {
return Stream.of(((OWLSubClassOfAxiom) ax).getSubClass().asOWLClass());
}
else if(ax instanceof OWLEquivalentClassesAxiom) {
return ((OWLEquivalentClassesAxiom) ax).getClassExpressionsAsList()
.stream()
.filter(IsAnonymous::isNamed)
.map(ce -> (OWLClass) ce);
}
else {
return Stream.empty();
}
})
.collect(toImmutableSet());
}
@Override
public boolean isLeaf(OWLClass object) {
return classHierarchyChildrenAxiomsIndex.isLeaf(object);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy