/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.processor;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.PMDException;
import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.RuleSetFactory;
import net.sourceforge.pmd.RuleSetNotFoundException;
import net.sourceforge.pmd.RuleSets;
import net.sourceforge.pmd.SourceCodeProcessor;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.util.datasource.DataSource;
public class PmdRunnable implements Callable<Report> {
private static final Logger LOG = Logger.getLogger(PmdRunnable.class.getName());
private static final ThreadLocal<ThreadContext> LOCAL_THREAD_CONTEXT = new ThreadLocal<>();
private final PMDConfiguration configuration;
private final DataSource dataSource;
private final String fileName;
private final List<Renderer> renderers;
private final RuleContext ruleContext;
private final RuleSetFactory ruleSetFactory;
private final SourceCodeProcessor sourceCodeProcessor;
public PmdRunnable(PMDConfiguration configuration, DataSource dataSource, String fileName,
List<Renderer> renderers, RuleContext ruleContext, RuleSetFactory ruleSetFactory,
SourceCodeProcessor sourceCodeProcessor) {
this.configuration = configuration;
this.dataSource = dataSource;
this.fileName = fileName;
this.renderers = renderers;
this.ruleContext = ruleContext;
this.ruleSetFactory = ruleSetFactory;
this.sourceCodeProcessor = sourceCodeProcessor;
}
public static void reset() {
LOCAL_THREAD_CONTEXT.remove();
}
private void addError(Report report, Exception e, String errorMessage) {
// unexpected exception: log and stop executor service
LOG.log(Level.FINE, errorMessage, e);
report.addError(new Report.ProcessingError(e.getMessage(), fileName));
}
@Override
public Report call() {
ThreadContext tc = LOCAL_THREAD_CONTEXT.get();
if (tc == null) {
try {
tc = new ThreadContext(ruleSetFactory.createRuleSets(configuration.getRuleSets()),
new RuleContext(ruleContext));
} catch (RuleSetNotFoundException e) {
throw new RuntimeException(e);
}
LOCAL_THREAD_CONTEXT.set(tc);
}
Report report = PMD.setupReport(tc.ruleSets, tc.ruleContext, fileName);
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Processing " + tc.ruleContext.getSourceCodeFilename());
}
for (Renderer r : renderers) {
r.startFileAnalysis(dataSource);
}
try {
InputStream stream = new BufferedInputStream(dataSource.getInputStream());
tc.ruleContext.setLanguageVersion(null);
sourceCodeProcessor.processSourceCode(stream, tc.ruleSets, tc.ruleContext);
} catch (PMDException pmde) {
addError(report, pmde, "Error while processing file: " + fileName);
} catch (IOException ioe) {
addError(report, ioe, "IOException during processing of " + fileName);
} catch (RuntimeException re) {
addError(report, re, "RuntimeException during processing of " + fileName);
}
return report;
}
private static class ThreadContext {
/* default */ final RuleSets ruleSets;
/* default */ final RuleContext ruleContext;
ThreadContext(RuleSets ruleSets, RuleContext ruleContext) {
this.ruleSets = ruleSets;
this.ruleContext = ruleContext;
}
}
}