1 package net.sourceforge.pmd.processor;
2
3 import java.io.BufferedInputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.util.List;
7 import java.util.concurrent.Callable;
8 import java.util.concurrent.ExecutorService;
9 import java.util.logging.Level;
10 import java.util.logging.Logger;
11
12 import net.sourceforge.pmd.PMDConfiguration;
13 import net.sourceforge.pmd.PMD;
14 import net.sourceforge.pmd.PMDException;
15 import net.sourceforge.pmd.Report;
16 import net.sourceforge.pmd.RuleContext;
17 import net.sourceforge.pmd.RuleSetFactory;
18 import net.sourceforge.pmd.RuleSets;
19 import net.sourceforge.pmd.renderers.Renderer;
20 import net.sourceforge.pmd.util.datasource.DataSource;
21
22 public class PmdRunnable extends PMD implements Callable<Report> {
23
24 private static final Logger LOG = Logger.getLogger(PmdRunnable.class.getName());
25
26 private final ExecutorService executor;
27 private final DataSource dataSource;
28 private final String fileName;
29 private final List<Renderer> renderers;
30
31 public PmdRunnable(ExecutorService executor,
32 PMDConfiguration configuration, DataSource dataSource,
33 String fileName, List<Renderer> renderers) {
34 super(configuration);
35 this.executor = executor;
36 this.dataSource = dataSource;
37 this.fileName = fileName;
38 this.renderers = renderers;
39 }
40
41
42 private static void addError(Report report, Exception ex, String fileName) {
43 report.addError(
44 new Report.ProcessingError(ex.getMessage(),
45 fileName)
46 );
47 }
48
49 private void addErrorAndShutdown(Report report, Exception e, String errorMessage) {
50
51 LOG.log(Level.FINE, errorMessage, e);
52 addError(report, e, fileName);
53 executor.shutdownNow();
54 }
55
56 public Report call() {
57 PmdThread thread = (PmdThread) Thread.currentThread();
58
59 RuleContext ctx = thread.getRuleContext();
60 RuleSets rs = thread.getRuleSets(configuration.getRuleSets());
61
62 Report report = setupReport(rs, ctx, fileName);
63
64 if (LOG.isLoggable(Level.FINE)) {
65 LOG.fine("Processing " + ctx.getSourceCodeFilename());
66 }
67 for (Renderer r : renderers) {
68 r.startFileAnalysis(dataSource);
69 }
70
71 try {
72 InputStream stream = new BufferedInputStream(
73 dataSource.getInputStream());
74 ctx.setLanguageVersion(null);
75 this.getSourceCodeProcessor().processSourceCode(stream, rs, ctx);
76 } catch (PMDException pmde) {
77 LOG.log(Level.FINE, "Error while processing file", pmde.getCause());
78 addError(report, pmde, fileName);
79 } catch (IOException ioe) {
80 addErrorAndShutdown(report, ioe, "IOException during processing");
81
82 } catch (RuntimeException re) {
83 addErrorAndShutdown(report, re,"RuntimeException during processing");
84 }
85 return report;
86 }
87
88 private static class PmdThread extends Thread {
89
90 public PmdThread(int id, Runnable r, RuleSetFactory ruleSetFactory,
91 RuleContext ctx) {
92 super(r, "PmdThread " + id);
93 this.id = id;
94 context = new RuleContext(ctx);
95 this.ruleSetFactory = ruleSetFactory;
96 }
97
98 private final int id;
99 private RuleContext context;
100 private RuleSets rulesets;
101 private final RuleSetFactory ruleSetFactory;
102
103 public RuleContext getRuleContext() {
104 return context;
105 }
106
107 public RuleSets getRuleSets(String rsList) {
108 if (rulesets == null) {
109 try {
110 rulesets = ruleSetFactory.createRuleSets(rsList);
111 } catch (Exception e) {
112 e.printStackTrace();
113 }
114 }
115 return rulesets;
116 }
117
118 @Override
119 public String toString() {
120 return "PmdThread " + id;
121 }
122 }
123
124 public static Thread createThread(int id, Runnable r,
125 RuleSetFactory ruleSetFactory, RuleContext ctx) {
126 return new PmdThread(id, r,ruleSetFactory, ctx);
127 }
128 }