
edu.stanford.protege.webprotege.revision.ProjectChangesManager Maven / Gradle / Ivy
The newest version!
package edu.stanford.protege.webprotege.revision;
import com.google.common.base.Stopwatch;
import com.google.common.collect.*;
import edu.stanford.protege.webprotege.axiom.AxiomIRISubjectProvider;
import edu.stanford.protege.webprotege.change.OntologyChange;
import edu.stanford.protege.webprotege.change.ProjectChange;
import edu.stanford.protege.webprotege.diff.DiffElement;
import edu.stanford.protege.webprotege.diff.DiffElementRenderer;
import edu.stanford.protege.webprotege.diff.Revision2DiffElementsTranslator;
import edu.stanford.protege.webprotege.inject.ProjectSingleton;
import edu.stanford.protege.webprotege.common.Page;
import edu.stanford.protege.webprotege.common.PageRequest;
import edu.stanford.protege.webprotege.common.ProjectId;
import edu.stanford.protege.webprotege.renderer.RenderingManager;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import javax.inject.Provider;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
/**
* Matthew Horridge
* Stanford Center for Biomedical Informatics Research
* 27/05/15
*/
@ProjectSingleton
public class ProjectChangesManager {
private static final Logger logger = LoggerFactory.getLogger(ProjectChangesManager.class);
public static final int DEFAULT_CHANGE_LIMIT = 50;
private final ProjectId projectId;
private final RevisionManager revisionManager;
private final RenderingManager browserTextProvider;
private final Comparator changeRecordComparator;
private final Provider revision2DiffElementsTranslatorProvider;
private final Table, ImmutableList> cache = HashBasedTable.create();
@Inject
public ProjectChangesManager(ProjectId projectId,
@Nonnull RevisionManager revisionManager,
@Nonnull RenderingManager browserTextProvider,
@Nonnull Comparator changeRecordComparator,
@Nonnull Provider revision2DiffElementsTranslatorProvider) {
this.projectId = projectId;
this.revisionManager = revisionManager;
this.browserTextProvider = browserTextProvider;
this.changeRecordComparator = changeRecordComparator;
this.revision2DiffElementsTranslatorProvider = revision2DiffElementsTranslatorProvider;
}
private static Multimap, OntologyChange> getChangesBySubject(Revision revision) {
Multimap, OntologyChange> results = HashMultimap.create();
revision.getChanges().forEach(record -> results.put(getSubject(record), record));
return results;
}
private static Optional getSubject(OntologyChange change) {
if (change.isAxiomChange()) {
var axiom = change.getAxiomOrThrow();
return getSubject(axiom);
}
else {
return Optional.empty();
}
}
private static Optional getSubject(OWLAxiom axiom) {
AxiomIRISubjectProvider subjectProvider = new AxiomIRISubjectProvider(IRI::compareTo);
return subjectProvider.getSubject(axiom);
}
public Page getProjectChanges(Optional subject,
PageRequest pageRequest) {
ImmutableList revisions = revisionManager.getRevisions();
if (subject.isPresent()) {
// We need to scan revisions to find the ones containing a particular subject
// We ignore the page request here.
// This needs reworking really, but the number of changes per entity is usually small
// so this works for now.
ImmutableList.Builder changes = ImmutableList.builder();
for (Revision revision : revisions) {
getProjectChangesForRevision(revision, subject, changes);
}
ImmutableList theChanges = changes.build();
return Page.create(1, 1, theChanges, theChanges.size());
}
else {
// Pages are in reverse order
ImmutableList.Builder changes = ImmutableList.builder();
revisions.reverse().stream()
.skip(pageRequest.getSkip())
.limit(pageRequest.getPageSize())
.forEach(revision -> getProjectChangesForRevision(revision, subject, changes));
ImmutableList changeList = changes.build();
int pageCount = (revisions.size() / pageRequest.getPageSize()) + 1;
return Page.create(pageRequest.getPageNumber(),
pageCount,
changeList, changeList.size());
}
}
public ImmutableList getProjectChangesForSubjectInRevision(OWLEntity subject, Revision revision) {
ImmutableList.Builder resultBuilder = ImmutableList.builder();
getProjectChangesForRevision(revision, Optional.of(subject), resultBuilder);
return resultBuilder.build();
}
private void getProjectChangesForRevision(Revision revision,
Optional subject,
ImmutableList.Builder changesBuilder) {
if(!cache.containsRow(revision.getRevisionNumber())) {
logger.debug("{} Building cache for revision {}", projectId, revision.getRevisionNumber().getValue());
var stopwatch = Stopwatch.createStarted();
var changeRecordsBySubject = getChangesBySubject(revision);
changeRecordsBySubject.asMap().forEach((subj, records) -> {
cache.put(revision.getRevisionNumber(), subj, ImmutableList.copyOf(records));
});
logger.debug("{} Cached revision {} in {} ms", projectId, revision.getRevisionNumber().getValue(), stopwatch.elapsed(TimeUnit.MILLISECONDS));
}
List limitedRecords = new ArrayList<>();
final int totalChanges;
if (subject.isPresent()) {
List records = cache.get(revision.getRevisionNumber(), subject.map(OWLEntity::getIRI));
if (records == null) {
// Nothing in this revision that changes the subject
return;
}
totalChanges = records.size();
limitedRecords.addAll(records);
}
else {
totalChanges = revision.getSize();
revision.getChanges().stream()
.limit(DEFAULT_CHANGE_LIMIT)
.forEach(limitedRecords::add);
}
Revision2DiffElementsTranslator translator = revision2DiffElementsTranslatorProvider.get();
List> axiomDiffElements = translator.getDiffElementsFromRevision(limitedRecords);
sortDiff(axiomDiffElements);
List> renderedDiffElements = renderDiffElements(axiomDiffElements);
int pageElements = renderedDiffElements.size();
int pageCount;
if (pageElements == 0) {
pageCount = 1;
}
else {
pageCount = totalChanges / pageElements + (totalChanges % pageElements);
}
Page> page = Page.create(
1,
pageCount,
renderedDiffElements,
totalChanges
);
ProjectChange projectChange = ProjectChange.get(
revision.getRevisionNumber(),
revision.getUserId(),
revision.getTimestamp(),
revision.getHighLevelDescription(),
totalChanges,
page);
changesBuilder.add(projectChange);
}
private List> renderDiffElements(List> axiomDiffElements) {
List> diffElements = new ArrayList<>();
DiffElementRenderer renderer = new DiffElementRenderer<>(browserTextProvider);
for (DiffElement axiomDiffElement : axiomDiffElements) {
diffElements.add(renderer.render(axiomDiffElement));
}
return diffElements;
}
private void sortDiff(List> diffElements) {
Comparator> c =
Comparator
.comparing((Function, OntologyChange>)
DiffElement::getLineElement, changeRecordComparator)
.thenComparing(DiffElement::getDiffOperation)
.thenComparing(DiffElement::getSourceDocument);
diffElements.sort(c);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy