View Javadoc

1   /***
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.ant;
5   
6   import net.sourceforge.pmd.PMD;
7   import net.sourceforge.pmd.PMDException;
8   import net.sourceforge.pmd.Report;
9   import net.sourceforge.pmd.Rule;
10  import net.sourceforge.pmd.RuleContext;
11  import net.sourceforge.pmd.RuleSet;
12  import net.sourceforge.pmd.RuleSetFactory;
13  import net.sourceforge.pmd.RuleSetNotFoundException;
14  import net.sourceforge.pmd.RuleSets;
15  import net.sourceforge.pmd.SimpleRuleSetNameMapper;
16  import net.sourceforge.pmd.SourceType;
17  import org.apache.tools.ant.AntClassLoader;
18  import org.apache.tools.ant.BuildException;
19  import org.apache.tools.ant.DirectoryScanner;
20  import org.apache.tools.ant.Project;
21  import org.apache.tools.ant.Task;
22  import org.apache.tools.ant.types.FileSet;
23  import org.apache.tools.ant.types.Path;
24  import org.apache.tools.ant.types.Reference;
25  
26  import java.io.BufferedInputStream;
27  import java.io.File;
28  import java.io.FileInputStream;
29  import java.io.FileNotFoundException;
30  import java.io.PrintWriter;
31  import java.io.StringWriter;
32  import java.util.ArrayList;
33  import java.util.Collection;
34  import java.util.Iterator;
35  import java.util.List;
36  
37  public class PMDTask extends Task {
38  
39      private Path classpath;
40      private List formatters = new ArrayList();
41      private List filesets = new ArrayList();
42      private int minPriority = Rule.LOWEST_PRIORITY;
43      private boolean shortFilenames;
44      private String ruleSetFiles;
45      private String encoding = System.getProperty("file.encoding");
46      private boolean failOnError;
47      private boolean failOnRuleViolation;
48      private String targetJDK = "1.4";
49      private String failuresPropertyName;
50      private String excludeMarker;
51      private final Collection nestedRules = new ArrayList();
52  
53      public void setShortFilenames(boolean value) {
54          this.shortFilenames = value;
55      }
56  
57      public void setTargetJDK(String value) {
58          this.targetJDK = value;
59      }
60  
61      public void setExcludeMarker(String value) {
62          this.excludeMarker = value;
63      }
64  
65      public void setFailOnError(boolean fail) {
66          this.failOnError = fail;
67      }
68  
69      public void setFailOnRuleViolation(boolean fail) {
70          this.failOnRuleViolation = fail;
71      }
72  
73      public void setRuleSetFiles(String ruleSetFiles) {
74          this.ruleSetFiles = ruleSetFiles;
75      }
76  
77      public void setEncoding(String encoding) {
78          this.encoding = encoding;
79      }
80  
81      public void setFailuresPropertyName(String failuresPropertyName) {
82          this.failuresPropertyName = failuresPropertyName;
83      }
84  
85      public void setMinimumPriority(int minPriority) {
86          this.minPriority = minPriority;
87      }
88  
89      public void addFileset(FileSet set) {
90          filesets.add(set);
91      }
92  
93      public void addFormatter(Formatter f) {
94          formatters.add(f);
95      }
96  
97      public void setClasspath(Path classpath) {
98          this.classpath = classpath;
99      }
100 
101     public Path getClasspath() {
102         return classpath;
103     }
104 
105     public Path createClasspath() {
106         if (classpath == null) {
107             classpath = new Path(getProject());
108         }
109         return classpath.createPath();
110     }
111 
112     public void setClasspathRef(Reference r) {
113         createLongClasspath().setRefid(r);
114     }
115 
116     public void execute() throws BuildException {
117         validate();
118 
119         ruleSetFiles = new SimpleRuleSetNameMapper(ruleSetFiles).getRuleSets();
120         RuleSets rules;
121         try {
122             RuleSetFactory ruleSetFactory = new RuleSetFactory();
123             ruleSetFactory.setMinimumPriority(minPriority);
124             if (classpath == null) {
125                 log("Using the normal ClassLoader", Project.MSG_VERBOSE);
126                 rules = ruleSetFactory.createRuleSets(ruleSetFiles);
127             } else {
128                 log("Using the AntClassLoader", Project.MSG_VERBOSE);
129                 rules = ruleSetFactory.createRuleSets(ruleSetFiles, new AntClassLoader(getProject(), classpath));
130             }
131         } catch (RuleSetNotFoundException e) {
132             throw new BuildException(e.getMessage());
133         }
134         logRulesUsed(rules);
135 
136         PMD pmd;
137         if (targetJDK.equals("1.3")) {
138             log("Targeting Java language version 1.3", Project.MSG_VERBOSE);
139             pmd = new PMD();
140             pmd.setJavaVersion(SourceType.JAVA_13);
141         } else if (targetJDK.equals("1.5")) {
142             log("Targeting Java language version 1.5", Project.MSG_VERBOSE);
143             pmd = new PMD();
144             pmd.setJavaVersion(SourceType.JAVA_15);
145         } else if(targetJDK.equals("jsp")){
146             log("Targeting JSP", Project.MSG_VERBOSE);
147             pmd = new PMD();
148             pmd.setJavaVersion(SourceType.JSP);
149         } else {
150             log("Targeting Java language version 1.4", Project.MSG_VERBOSE);
151             pmd = new PMD();
152         }
153 
154         if (excludeMarker != null) {
155             log("Setting exclude marker to be " + excludeMarker, Project.MSG_VERBOSE);
156             pmd.setExcludeMarker(excludeMarker);
157         }
158 
159         RuleContext ctx = new RuleContext();
160         Report report = new Report();
161         ctx.setReport(report);
162         report.start();
163         for (Iterator i = filesets.iterator(); i.hasNext();) {
164             FileSet fs = (FileSet) i.next();
165             DirectoryScanner ds = fs.getDirectoryScanner(getProject());
166             String[] srcFiles = ds.getIncludedFiles();
167             for (int j = 0; j < srcFiles.length; j++) {
168                 File file = new File(ds.getBasedir() + System.getProperty("file.separator") + srcFiles[j]);
169                 log("Processing file " + file.getAbsoluteFile().toString(), Project.MSG_VERBOSE);
170                 ctx.setSourceCodeFilename(shortFilenames ? srcFiles[j] : file.getAbsolutePath());
171                 try {
172                     pmd.processFile(new BufferedInputStream(new FileInputStream(file)), encoding, rules, ctx);
173                 } catch (FileNotFoundException fnfe) {
174                     if (failOnError) {
175                         throw new BuildException(fnfe);
176                     }
177                 } catch (PMDException pmde) {
178                     log(pmde.toString(), Project.MSG_VERBOSE);
179                     if (pmde.getReason() != null) {
180                         StringWriter strWriter = new StringWriter();
181                         PrintWriter printWriter = new PrintWriter(strWriter);
182                         pmde.getReason().printStackTrace(printWriter);
183                         log(strWriter.toString(), Project.MSG_VERBOSE);
184                     }
185                     if (pmde.getReason() != null && pmde.getReason().getMessage() != null) {
186                         log(pmde.getReason().getMessage(), Project.MSG_VERBOSE);
187                     }
188                     if (failOnError) {
189                         throw new BuildException(pmde);
190                     }
191                     ctx.getReport().addError(new Report.ProcessingError(pmde.getMessage(), ctx.getSourceCodeFilename()));
192                 }
193             }
194         }
195         report.end();
196 
197         log(ctx.getReport().size() + " problems found", Project.MSG_VERBOSE);
198 
199         for (Iterator i = formatters.iterator(); i.hasNext();) {
200             Formatter formatter = (Formatter) i.next();
201             log("Sending a report to " + formatter, Project.MSG_VERBOSE);
202             formatter.outputReport(ctx.getReport(), getProject().getBaseDir().toString());
203         }
204 
205         if (failuresPropertyName != null && ctx.getReport().size() > 0) {
206             getProject().setProperty(failuresPropertyName, String.valueOf(ctx.getReport().size()));
207             log("Setting property " + failuresPropertyName + " to " + String.valueOf(ctx.getReport().size()), Project.MSG_VERBOSE);
208         }
209 
210         if (failOnRuleViolation && ctx.getReport().size() > 0) {
211             throw new BuildException("Stopping build since PMD found " + ctx.getReport().size() + " rule violations in the code");
212         }
213     }
214 
215     private void logRulesUsed(net.sourceforge.pmd.RuleSets rules) {
216         log("Using these rulesets: " + ruleSetFiles, Project.MSG_VERBOSE);
217 
218         RuleSet[] ruleSets = rules.getAllRuleSets();
219         for (int j = 0; j < ruleSets.length; j++) {
220             RuleSet ruleSet = ruleSets[j];
221 
222             for (Iterator i = ruleSet.getRules().iterator(); i.hasNext();) {
223                 Rule rule = (Rule) i.next();
224                 log("Using rule " + rule.getName(), Project.MSG_VERBOSE);
225             }
226         }
227     }
228 
229     private void validate() throws BuildException {
230         // TODO - check for empty Formatters List here?
231         for (Iterator i = formatters.iterator(); i.hasNext();) {
232             Formatter f = (Formatter) i.next();
233             if (f.isNoOutputSupplied()) {
234                 throw new BuildException("toFile or toConsole needs to be specified in Formatter");
235             }
236         }
237 
238         if (ruleSetFiles == null) {
239             if (nestedRules.isEmpty()) {
240                 throw new BuildException("No rulesets specified");
241             }
242             ruleSetFiles = getNestedRuleSetFiles();
243         }
244 
245         if (!targetJDK.equals("1.3") && !targetJDK.equals("1.4") && !targetJDK.equals("1.5") && !targetJDK.equals("jsp")) {
246             throw new BuildException("The targetjdk attribute, if used, must be set to either '1.3', '1.4', or '1.5', or 'jsp'");
247         }
248     }
249 
250     private String getNestedRuleSetFiles() {
251         final StringBuffer sb = new StringBuffer();
252         for (Iterator it = nestedRules.iterator(); it.hasNext();) {
253             RuleSetWrapper rs = (RuleSetWrapper) it.next();
254             sb.append(rs.getFile());
255             if (it.hasNext()) {
256                 sb.append(',');
257             }
258         }
259         return sb.toString();
260     }
261 
262     private Path createLongClasspath() {
263         if (classpath == null) {
264             classpath = new Path(getProject());
265         }
266         return classpath.createPath();
267     }
268 
269     public void addRuleset(RuleSetWrapper r) {
270         nestedRules.add(r);
271     }
272 
273 }
274