package org.jbehave.eclipse.cache.container;
import static org.jbehave.eclipse.cache.container.Containers.modificationStampOf;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.jbehave.eclipse.util.Visitor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class Container<E> {
private Logger log = LoggerFactory.getLogger(Container.class);
private long timestamp = Containers.UNITIALIZED_STAMP;
private volatile int lastBuildTick;
protected final String containerName;
public Container(String containerName) {
this.containerName = containerName;
}
int getLastBuildTick() {
return lastBuildTick;
}
void setLastBuildTick(int traverseTick) {
while (this.lastBuildTick < traverseTick)
this.lastBuildTick = traverseTick;
}
abstract void recursivelyRemoveBuildOlderThan(int buildTick, IProgressMonitor monitor);
void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
boolean isTimestampDifferent(long timestamp) {
return this.timestamp != timestamp;
}
public abstract void traverse(Visitor<E, ?> visitor);
public abstract void clear();
public abstract void add(E element);
public abstract Container<E> specializeFor(IPackageFragmentRoot pkgFragmentRoot);
public abstract Container<E> specializeFor(IPackageFragment pkgFragment);
public abstract Container<E> specializeFor(ICompilationUnit cunit);
public boolean prepareForTraversal(IJavaElement element, int buildTick) {
setLastBuildTick(buildTick);
long timestamp = modificationStampOf(element);
log.debug("Preparing for traversal [" + element.getElementName() + "] in [" + Containers.pathOf(element) + "] ts: " + timestamp);
if (isTimestampDifferent(timestamp)) {
// clear and rescan
setTimestamp(timestamp);
clear();
log.debug("Change detected on [" + element.getElementName() + "] in [" + Containers.pathOf(element) + "] traversing!");
return true;
}
boolean traverse = shouldContinueTraversingEvenIfNotChanged(element);
log.debug("No change detected on [" + element.getElementName() + "] in [" + Containers.pathOf(element) + "] traverse anyway? " + traverse);
return traverse;
}
protected boolean shouldContinueTraversingEvenIfNotChanged(IJavaElement element) {
if (element.getElementType() == IJavaElement.COMPILATION_UNIT) {
return false;
}
// modification stamp does not reflect a modification deeper in hierarchy
// so one cannot rely on it for step modification in source file
// unless it an archive such as a jar or a source file...
// in other words it is possible for a step class to be modified, and the
// package not be stamped.
if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT_ROOT) {
try {
int kind = ((IPackageFragmentRoot) element).getKind();
if (kind == IPackageFragmentRoot.K_BINARY)
// archive would have changed if content changed...
return false;
} catch (JavaModelException e) {
log.warn("Failed to retrieve kind of " + element.getElementName() + "] in [" + Containers.pathOf(element), e);
}
}
return true;
}
public void resetForBuild(IJavaElement element, int buildTick) {
setLastBuildTick(buildTick);
long timestamp = modificationStampOf(element);
setTimestamp(timestamp);
clear();
}
}