edu.stanford.protege.webprotege.index.impl.AxiomMultimapIndex Maven / Gradle / Ivy
The newest version!
package edu.stanford.protege.webprotege.index.impl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
import edu.stanford.protege.webprotege.change.AxiomChange;
import edu.stanford.protege.webprotege.change.OntologyChange;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLOntologyID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.PrintStream;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Matthew Horridge
* Stanford Center for Biomedical Informatics Research
* 2019-09-07
*/
public class AxiomMultimapIndex {
private final AxiomChangeHandler axiomChangeHandler = new AxiomChangeHandler();
@Nonnull
private final Multimap, A> backingMap;
@Nullable
private final KeyValueExtractor unaryKeyValueExtractor;
@Nullable
private final KeyValueExtractor, A> naryKeyValueExtractor;
@Nonnull
private final Class axiomCls;
private final Queue> changeQueue = new ArrayDeque<>();
private volatile boolean lazy = false;
private boolean allowDuplicates = true;
public static AxiomMultimapIndex create(@Nonnull Class axiomCls,
@Nonnull KeyValueExtractor keyValueExtractor,
@Nonnull Multimap, A> backingMap) {
return new AxiomMultimapIndex<>(axiomCls, keyValueExtractor, null, backingMap);
}
public static AxiomMultimapIndex create(@Nonnull Class axiomCls,
@Nonnull KeyValueExtractor keyValueExtractor) {
var backingMap = IndexedSetMultimaps.create();
return new AxiomMultimapIndex<>(axiomCls, keyValueExtractor, null, backingMap);
}
public static AxiomMultimapIndex createWithNaryKeyValueExtractor(@Nonnull Class axiomCls,
@Nonnull KeyValueExtractor, A> keyValueExtractor) {
var backingMap = IndexedSetMultimaps.create();
return new AxiomMultimapIndex<>(axiomCls, null, keyValueExtractor, backingMap);
}
public static AxiomMultimapIndex createWithNaryKeyValueExtractor(@Nonnull Class axiomCls,
@Nonnull KeyValueExtractor, A> keyValueExtractor,
@Nonnull Multimap, A> backingMap) {
return new AxiomMultimapIndex<>(axiomCls, null, keyValueExtractor, backingMap);
}
private AxiomMultimapIndex(@Nonnull Class axiomCls,
@Nullable KeyValueExtractor unaryKeyValueExtractor,
@Nullable KeyValueExtractor, A> naryKeyValueExtractor,
@Nonnull Multimap, A> backingMap) {
this.backingMap = checkNotNull(backingMap);
this.unaryKeyValueExtractor = unaryKeyValueExtractor;
this.naryKeyValueExtractor = naryKeyValueExtractor;
this.axiomCls = checkNotNull(axiomCls);
axiomChangeHandler.setAxiomChangeConsumer(this::handleChange);
}
public void setLazy(boolean lazy) {
this.lazy = lazy;
}
public void setAllowDuplicates(boolean allowDuplicates) {
this.allowDuplicates = allowDuplicates;
}
private void handleChange(@Nonnull AxiomChange change) {
var axiom = change.getAxiom();
if(!axiomCls.isInstance(axiom)) {
return;
}
var ax = axiomCls.cast(axiom);
if(isNaryKeyValue()) {
var values = getNaryKeyValueExtractor(ax);
values.forEach(val -> {
var key = Key.get(change.getOntologyId(), val);
handleOntologyChange(change, key, ax);
});
}
else {
var keyValue = getUnaryKeyValueExtractor(ax);
if(keyValue == null) {
return;
}
var key = Key.get(change.getOntologyId(),
keyValue);
handleOntologyChange(change, key, ax);
}
}
private boolean isNaryKeyValue() {
return naryKeyValueExtractor != null;
}
@Nullable
private Iterable getNaryKeyValueExtractor(A ax) {
checkNotNull(naryKeyValueExtractor);
return naryKeyValueExtractor.extractValue(ax);
}
private void handleOntologyChange(@Nonnull AxiomChange change, Key key, A ax) {
if(change.isAddAxiom()) {
// Backing map may/may not be a set
// If it is a set then we just added the key/axiom pair
// If it is not a set, we don't want duplicates so we must
// check to see if it contains the key/axiom pair
var shouldAdd = allowDuplicates || backingMap instanceof SetMultimap || !backingMap.containsEntry(key, ax);
if(shouldAdd) {
backingMap.put(key, ax);
}
}
else {
backingMap.remove(key, ax);
}
}
private V getUnaryKeyValueExtractor(A ax) {
checkNotNull(unaryKeyValueExtractor);
return unaryKeyValueExtractor.extractValue(ax);
}
public synchronized Stream getAxioms(@Nonnull V value, @Nonnull OWLOntologyID ontologyId) {
var key = Key.get(ontologyId, value);
if(!changeQueue.isEmpty()) {
applyQueuedChanges();
}
return ImmutableList.copyOf(backingMap.get(key))
.stream();
}
private void applyQueuedChanges() {
while(!changeQueue.isEmpty()) {
var changes = changeQueue.poll();
axiomChangeHandler.handleOntologyChanges(changes);
}
}
public synchronized void applyChanges(@Nonnull ImmutableList changes) {
changeQueue.add(changes);
if(!lazy) {
applyQueuedChanges();
}
}
public void dumpStats(PrintStream out) {
Stats.dump("Index", backingMap, out);
}
public boolean hasValues(V cls, OWLOntologyID ontologyId) {
return backingMap.containsKey(Key.get(ontologyId, cls));
}
@Override
public String toString() {
return backingMap.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy