package net.unit8.waitt.feature.jacoco;
import net.unit8.waitt.api.ClassLoaderFactory;
import net.unit8.waitt.api.ConfigurableFeature;
import net.unit8.waitt.api.EmbeddedServer;
import net.unit8.waitt.api.ServerMonitor;
import net.unit8.waitt.api.configuration.WebappConfiguration;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.jacoco.agent.rt.internal_b0d6a23.Agent;
import org.jacoco.agent.rt.internal_b0d6a23.core.runtime.AgentOptions;
import org.jacoco.core.analysis.IBundleCoverage;
import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.tools.ExecFileLoader;
import org.jacoco.report.FileMultiReportOutput;
import org.jacoco.report.IReportGroupVisitor;
import org.jacoco.report.IReportVisitor;
import org.jacoco.report.MultiReportVisitor;
import org.jacoco.report.html.HTMLFormatter;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
/**
*
* @author kawasima
*/
public class JacocoMonitor implements ServerMonitor,ConfigurableFeature {
private static final Logger LOG = Logger.getLogger(JacocoMonitor.class.getName());
private Set<String> targetPackages;
private File sourceDirectory;
ExecutorService executorService;
@Override
public void config(WebappConfiguration config) {
targetPackages = config.getPackages();
sourceDirectory = config.getSourceDirectory();
}
@Override
public void init(EmbeddedServer server) {
final ClassRealm coverageRealm = (ClassRealm) this.getClass().getClassLoader();
server.setClassLoaderFactory(new ClassLoaderFactory() {
@Override
public ClassLoader create(ClassLoader parent) {
coverageRealm.setParentClassLoader(parent);
JacocoClassLoader ccl = JacocoClassLoader.create(coverageRealm);
ccl.setTargetPackages(targetPackages);
return ccl;
}
});
LOG.info("Start a jacoco agent. " + Agent.getInstance(new AgentOptions()));
}
@Override
public void start(EmbeddedServer server) {
File reportDirectory = new File("target/coverage");
if (!reportDirectory.exists()) {
reportDirectory.mkdirs();
}
server.addContext("/_coverage", reportDirectory.getAbsolutePath(), getClass().getClassLoader());
executorService = Executors.newCachedThreadPool();
final ExecFileLoader loader = new ExecFileLoader();
try {
loader.load(new File("jacoco.exec"));
} catch (IOException ignore) {}
executorService.execute(new Runnable() {
@Override
public void run() {
while(true) {
try {
Agent.getInstance().dump(false);
loader.load(new File("jacoco.exec"));
final IReportVisitor visitor = createVisitor(Locale.getDefault());
visitor.visitInfo(
loader.getSessionInfoStore().getInfos(),
loader.getExecutionDataStore().getContents());
createReport(visitor, loader.getExecutionDataStore());
visitor.visitEnd();
} catch (IOException ex) {
// ignore
}
try {
TimeUnit.SECONDS.sleep(30);
} catch (InterruptedException ignore) { /* ignore */ }
}
}
});
}
void createReport(final IReportGroupVisitor visitor, ExecutionDataStore executionDataStore) throws IOException {
final BundleCreator creator = new BundleCreator();
final IBundleCoverage bundle = creator.createBundle(executionDataStore);
List<File> sourceDirectories = new ArrayList<File>(1);
sourceDirectories.add(sourceDirectory);
final SourceFileCollection locator = new SourceFileCollection(sourceDirectories, "UTF-8");
visitor.visitBundle(bundle, locator);
}
IReportVisitor createVisitor(final Locale locale) throws IOException {
final List<IReportVisitor> visitors = new ArrayList<IReportVisitor>();
final HTMLFormatter htmlFormatter = new HTMLFormatter();
htmlFormatter.setOutputEncoding("UTF-8");
htmlFormatter.setLocale(locale);
visitors.add(htmlFormatter.createVisitor(new FileMultiReportOutput(new File("target/coverage"))));
return new MultiReportVisitor(visitors);
}
@Override
public void stop() {
executorService.shutdown();
}
}