package de.hub.srcrepo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.eclipse.gmt.modisco.java.emf.JavaPackage;
import com.google.common.base.Preconditions;
import de.hub.jstattrack.TimeStatistic;
import de.hub.jstattrack.TimeStatistic.Timer;
import de.hub.jstattrack.ValueStatistic;
import de.hub.jstattrack.services.BatchedPlot;
import de.hub.jstattrack.services.Summary;
import de.hub.srcrepo.repositorymodel.JavaCompilationUnitRef;
import de.hub.srcrepo.repositorymodel.RepositoryModel;
import de.hub.srcrepo.repositorymodel.Rev;
import de.hub.srcrepo.snapshot.IModiscoIncrementalSnapshotModel;
import de.hub.srcrepo.snapshot.IModiscoSnapshotModel;
import de.hub.srcrepo.snapshot.ModiscoIncrementalSnapshotImpl;
public abstract class MoDiscoRevVisitor extends ProjectAwareRevVisitor {
public static final ValueStatistic revSnapshotCountStat = new ValueStatistic().with(Summary.class).with(BatchedPlot.class).register(MoDiscoRevVisitor.class, "SnapshotCount");
public static final ValueStatistic revCUCountStat = new ValueStatistic().with(Summary.class).with(BatchedPlot.class).register(MoDiscoRevVisitor.class, "CUCount");
public static final ValueStatistic revChangedCUCountStat = new ValueStatistic().with(Summary.class).with(BatchedPlot.class).register(MoDiscoRevVisitor.class, "ChangedCUCount");
public static final TimeStatistic revComputeSSETStat = new TimeStatistic(TimeUnit.MICROSECONDS).with(Summary.class).with(BatchedPlot.class).register(MoDiscoRevVisitor.class, "revComputeSnapshotET");
public static final TimeStatistic revUDFETStat = new TimeStatistic(TimeUnit.MICROSECONDS).with(Summary.class).with(BatchedPlot.class).register(MoDiscoRevVisitor.class, "revSnapshotUDFET");
private int count = 0;
private final IModiscoIncrementalSnapshotModel.Factory snapshotFactory;
private final Map<String, IModiscoIncrementalSnapshotModel> snapshots;
public MoDiscoRevVisitor(IModiscoIncrementalSnapshotModel.Factory snapshotFactory) {
super();
this.snapshotFactory = snapshotFactory;
snapshots = new HashMap<String, IModiscoIncrementalSnapshotModel>();
}
public MoDiscoRevVisitor(JavaPackage metaModel) {
this(new IModiscoIncrementalSnapshotModel.Factory() {
@Override
public IModiscoIncrementalSnapshotModel create(String projectID) {
return new ModiscoIncrementalSnapshotImpl(metaModel, projectID);
}
});
}
@Override
public void onRev(Rev rev, Rev traversalParentRev) {
SrcRepoActivator.INSTANCE.info("Visiting revision: " + rev.getName() + "(" + (++count) + "/" + ((RepositoryModel)rev.eContainer()).getAllRevs().size() + ")");
super.onRev(rev, traversalParentRev);
}
@Override
protected final void onRev(Rev rev, Rev traversalParentRev, Map<String,Map<String,JavaCompilationUnitRef>> projectFiles) {
Timer computeSnapshotTimer = revComputeSSETStat.timer();
if (!filter(rev)) {
return;
}
// remove projects that do not longer exist
List<String> projectsToRemove = null;
for(String projectID: snapshots.keySet()) {
if (projectFiles.get(projectID)==null){
if (projectsToRemove == null) {
projectsToRemove = new ArrayList<String>();
}
projectsToRemove.add(projectID);
}
}
if (projectsToRemove != null) {
for (String projectID: projectsToRemove) {
snapshots.remove(projectID).clear();
}
}
// update projects
int snapshotCount = 0;
int cuCount = 0;
int changedCUsTotal = 0;
ProjectLoop: for(String projectID: projectFiles.keySet()) {
Preconditions.checkArgument(projectID != null);
Map<String,JavaCompilationUnitRef> files = projectFiles.get(projectID);
snapshotCount++;
IModiscoIncrementalSnapshotModel snapshot = snapshots.get(projectID);
if (snapshot == null) {
if (files.isEmpty()) {
continue ProjectLoop;
}
snapshot = snapshotFactory.create(projectID);
snapshots.put(projectID, snapshot);
}
int changedCUsInSnapshot = 0;
try {
snapshot.start();
// merge the models from all compilation units
Collection<String> pathsInFiles = new HashSet<String>();
for (Map.Entry<String, JavaCompilationUnitRef> entry : files.entrySet()) {
cuCount++;
String path = entry.getKey();
pathsInFiles.add(path);
JavaCompilationUnitRef newRef = entry.getValue();
JavaCompilationUnitRef oldRef = snapshot.getContributingRef(path);
if (newRef != oldRef) {
if (oldRef != null) {
snapshot.removeCompilationUnitModel(path, oldRef);
}
snapshot.addCompilationUnitModel(path, newRef);
changedCUsInSnapshot++;
}
}
for (String path : new ArrayList<String>(snapshot.getContributingRefs())) {
if (!pathsInFiles.contains(path)) {
snapshot.removeCompilationUnitModel(path, snapshot.getContributingRef(path));
changedCUsInSnapshot++;
}
}
if (!snapshot.end()) {
throw new RuntimeException("try again.");
}
changedCUsTotal += changedCUsInSnapshot;
} catch (Exception incrementalException) {
// something unexpected happend. Loose the failed snapshot and start from scratch
SrcRepoActivator.INSTANCE.warning("Could not update a snapshot; replaced snapshot with a fresh one.", incrementalException);
try {
if (!snapshot.rebuild()) {
SrcRepoActivator.INSTANCE.warning("There were also warnings creating the snapshots, Ill continue anyways.");
}
} catch (Exception newException) {
SrcRepoActivator.INSTANCE.warning("Also could not create a fresh snapshot. Will try to create one for next revision.", newException);
continue ProjectLoop;
}
}
try {
if (changedCUsInSnapshot > 0) {
SrcRepoActivator.INSTANCE.info("Updated snapshot for " + projectID + ", number of changed CUs " + changedCUsInSnapshot);
Timer udfTimer = revUDFETStat.timer();
try {
onRev(rev, traversalParentRev, projectID, snapshot);
} catch (Exception e) {
SrcRepoActivator.INSTANCE.error("Exception in visitor UDF.", e);
}
udfTimer.track();
}
} catch (Exception e) {
SrcRepoActivator.INSTANCE.warning("There was an exception thrown in UDF.", e);
}
}
computeSnapshotTimer.track();
revSnapshotCountStat.track(snapshotCount);
revCUCountStat.track(cuCount);
revChangedCUCountStat.track(changedCUsTotal);
Timer udfTimer = revUDFETStat.timer();
try {
onRevWithSnapshots(rev, traversalParentRev, snapshots);
} catch (Exception e) {
SrcRepoActivator.INSTANCE.error("Exception in visitor UDF.", e);
}
udfTimer.track();
}
protected boolean filter(Rev rev) {
return true;
}
protected abstract void onRev(Rev rev, Rev traversalParentRev, String projectID, IModiscoSnapshotModel snapshot);
protected void onRevWithSnapshots(Rev rev, Rev traversalParentRev, Map<String, ? extends IModiscoSnapshotModel> snapshot) {
}
}