View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd;
5   
6   import java.io.IOException;
7   import java.util.Arrays;
8   import java.util.List;
9   import java.util.Properties;
10  
11  import net.sourceforge.pmd.lang.LanguageRegistry;
12  import net.sourceforge.pmd.lang.LanguageVersion;
13  import net.sourceforge.pmd.lang.LanguageVersionDiscoverer;
14  import net.sourceforge.pmd.renderers.Renderer;
15  import net.sourceforge.pmd.renderers.RendererFactory;
16  import net.sourceforge.pmd.util.ClasspathClassLoader;
17  import net.sourceforge.pmd.util.IOUtil;
18  
19  /**
20   * This class contains the details for the runtime configuration of PMD.
21   * There are several aspects to the configuration of PMD.
22   * <p>
23   * The aspects related to generic PMD behavior:
24   * <ul>
25   * 	<li>Suppress marker is used in source files to suppress a RuleViolation,
26   *	    defaults to {@link PMD#SUPPRESS_MARKER}.
27   *          {@link #getSuppressMarker()}</li>
28   *  <li>The number of threads to create when invoking on multiple files,
29   *      defaults one thread per available processor.
30   *          {@link #getThreads()}</li>
31   *  <li>A ClassLoader to use when loading classes during Rule processing
32   *      (e.g. during type resolution), defaults to ClassLoader of the
33   *      Configuration class.
34   *          {@link #getClassLoader()}</li>
35   *  <li>A means to configure a ClassLoader using a prepended classpath
36   *     String, instead of directly setting it programmatically.
37   *          {@link #prependClasspath(String)}</li>
38   *  <li>A LanguageVersionDiscoverer instance, which defaults to using the
39   *      default LanguageVersion of each Language.  Means are provided to
40   *      change the LanguageVersion for each Language.
41   *          {@link #getLanguageVersionDiscoverer()}</li>
42   * </ul>
43   * <p>
44   * The aspects related to Rules and Source files are:
45   * <ul>
46   *  <li>A comma separated list of RuleSets URIs.
47   *          {@link #getRuleSets()}</li>
48   *  <li>A minimum priority threshold when loading Rules from RuleSets,
49   *      defaults to {@link RulePriority#LOW}.
50   *          {@link #getMinimumPriority()}</li>
51   *  <li>The character encoding of source files, defaults to the system default
52   *      as returned by <code>System.getProperty("file.encoding")</code>.
53   *          {@link #getSourceEncoding()}</li>
54   *  <li>A comma separated list of input paths to process for source files.
55   *      This may include files, directories, archives (e.g. ZIP files), etc.
56   *          {@link #getInputPaths()}</li>
57   * </ul>
58   * <p>
59   * <ul>
60   *  <li>The renderer format to use for Reports.
61   *          {@link #getReportFormat()}</li>
62   *  <li>The file to which the Report should render.
63   *          {@link #getReportFile()}</li>
64   *  <li>An indicator of whether to use File short names in Reports, defaults
65   *      to <code>false</code>.
66   *          {@link #isReportShortNames()}</li>
67   *  <li>The initialization properties to use when creating a Renderer instance.
68   *          {@link #getReportProperties()}</li>
69   *  <li>An indicator of whether to show suppressed Rule violations in Reports.
70   *          {@link #isShowSuppressedViolations()}</li>
71   * </ul>
72   * <p>
73   * The aspects related to special PMD behavior are:
74   * <ul>
75   *  <li>An indicator of whether PMD should log debug information.
76   *          {@link #isDebug()}</li>
77   *  <li>An indicator of whether PMD should perform stress testing behaviors,
78   *          such as randomizing the order of file processing.
79   *          {@link #isStressTest()}</li>
80   *  <li>An indicator of whether PMD should log benchmarking information.
81   *          {@link #isBenchmark()}</li>
82   * </ul>
83   */
84  public class PMDConfiguration extends AbstractConfiguration {
85  
86      // General behavior options
87      private String suppressMarker = PMD.SUPPRESS_MARKER;
88      private int threads = Runtime.getRuntime().availableProcessors();
89      private ClassLoader classLoader = getClass().getClassLoader();
90      private LanguageVersionDiscoverer languageVersionDiscoverer = new LanguageVersionDiscoverer();
91  
92      // Rule and source file options
93      private String ruleSets;
94      private RuleSets pmdRuleSets;
95      private RulePriority minimumPriority = RulePriority.LOW;
96      private String inputPaths;
97      private String inputUri;
98  
99      // Reporting options
100     private String reportFormat;
101     private String reportFile;
102     private boolean reportShortNames = false;
103     private Properties reportProperties = new Properties();
104     private boolean showSuppressedViolations = false;
105     private boolean failOnViolation = true;
106 
107     private boolean stressTest;
108     private boolean benchmark;
109 
110     /**
111      * Get the suppress marker. This is the source level marker used to indicate a
112      * RuleViolation should be suppressed.
113      * 
114      * @return The suppress marker.
115      */
116     public String getSuppressMarker() {
117         return suppressMarker;
118     }
119 
120     /**
121      * Set the suppress marker.
122      * 
123      * @param suppressMarker
124      *            The suppress marker to use.
125      */
126     public void setSuppressMarker(String suppressMarker) {
127         this.suppressMarker = suppressMarker;
128     }
129 
130     /**
131      * Get the number of threads to use when processing Rules.
132      * 
133      * @return The number of threads.
134      */
135     public int getThreads() {
136         return threads;
137     }
138 
139     /**
140      * Set the number of threads to use when processing Rules.
141      * 
142      * @param threads
143      *            The number of threads.
144      */
145     public void setThreads(int threads) {
146         this.threads = threads;
147     }
148 
149     /**
150      * Get the ClassLoader being used by PMD when processing Rules.
151      * 
152      * @return The ClassLoader being used
153      */
154     public ClassLoader getClassLoader() {
155         return classLoader;
156     }
157 
158     /**
159      * Set the ClassLoader being used by PMD when processing Rules. Setting a
160      * value of <code>null</code> will cause the default ClassLoader to be used.
161      * 
162      * @param classLoader
163      *            The ClassLoader to use
164      */
165     public void setClassLoader(ClassLoader classLoader) {
166         if (classLoader == null) {
167             this.classLoader = getClass().getClassLoader();
168         } else {
169             this.classLoader = classLoader;
170         }
171     }
172 
173     /**
174      * Prepend the specified classpath like string to the current ClassLoader of
175      * the configuration. If no ClassLoader is currently configured, the
176      * ClassLoader used to load the {@link PMDConfiguration} class will be used
177      * as the parent ClassLoader of the created ClassLoader.
178      * <p>
179      * If the classpath String looks like a URL to a file (i.e. starts with
180      * <code>file://</code>) the file will be read with each line representing
181      * an entry on the classpath.
182      * 
183      * @param classpath The prepended classpath.
184      * @throws IOException if the given classpath is invalid (e.g. does not exist)
185      * @see PMDConfiguration#setClassLoader(ClassLoader)
186      * @see ClasspathClassLoader
187      */
188     public void prependClasspath(String classpath) throws IOException {
189         if (classLoader == null) {
190             classLoader = PMDConfiguration.class.getClassLoader();
191         }
192         if (classpath != null) {
193             classLoader = new ClasspathClassLoader(classpath, classLoader);
194         }
195     }
196 
197     /**
198      * Get the LanguageVersionDiscoverer, used to determine the LanguageVersion
199      * of a source file.
200      * 
201      * @return The LanguageVersionDiscoverer.
202      */
203     public LanguageVersionDiscoverer getLanguageVersionDiscoverer() {
204         return languageVersionDiscoverer;
205     }
206 
207     /**
208      * Set the given LanguageVersion as the current default for it's Language.
209      * 
210      * @param languageVersion
211      *            the LanguageVersion
212      */
213     public void setDefaultLanguageVersion(LanguageVersion languageVersion) {
214         setDefaultLanguageVersions(Arrays.asList(languageVersion));
215     }
216 
217     /**
218      * Set the given LanguageVersions as the current default for their
219      * Languages.
220      * 
221      * @param languageVersions
222      *            The LanguageVersions.
223      */
224     public void setDefaultLanguageVersions(List<LanguageVersion> languageVersions) {
225         for (LanguageVersion languageVersion : languageVersions) {
226             languageVersionDiscoverer.setDefaultLanguageVersion(languageVersion);
227         }
228     }
229 
230     /**
231      * Get the LanguageVersion of the source file with given name. This depends
232      * on the fileName extension, and the java version.
233      * <p/>
234      * For compatibility with older code that does not always pass in a correct
235      * filename, unrecognized files are assumed to be java files.
236      * 
237      * @param fileName
238      *            Name of the file, can be absolute, or simple.
239      * @return the LanguageVersion
240      */
241     // FUTURE Delete this? I can't think of a good reason to keep it around.
242     // Failure to determine the LanguageVersion for a file should be a hard
243     // error, or simply cause the file to be skipped?
244     public LanguageVersion getLanguageVersionOfFile(String fileName) {
245         LanguageVersion languageVersion = languageVersionDiscoverer.getDefaultLanguageVersionForFile(fileName);
246         if (languageVersion == null) {
247             // For compatibility with older code that does not always pass in
248             // a correct filename.
249             languageVersion = languageVersionDiscoverer.getDefaultLanguageVersion(LanguageRegistry.getLanguage("Java"));
250         }
251         return languageVersion;
252     }
253 
254     /**
255      * Get the comma separated list of RuleSet URIs.
256      * 
257      * @return The RuleSet URIs.
258      */
259     public String getRuleSets() {
260         return ruleSets;
261     }
262 
263     /**
264      * Set the comma separated list of RuleSet URIs.
265      * 
266      * @param ruleSets the rulesets to set
267      */
268     public void setRuleSets(String ruleSets) {
269         this.ruleSets = ruleSets;
270     }
271 
272     /**
273      * Get the RuleSets.
274      * 
275      * @return the pmdRuleSets
276      */
277     public RuleSets getPmdRuleSets() {
278         return pmdRuleSets;
279     }
280 
281     /**
282      * Set the RuleSets
283      * 
284      * @param pmdRuleSets the pmdRuleSets to set
285      */
286     public void setPmdRuleSets(RuleSets pmdRuleSets) {
287         this.pmdRuleSets = pmdRuleSets;
288     }
289 
290     /**
291      * Get the minimum priority threshold when loading Rules from RuleSets.
292      * 
293      * @return The minimum priority threshold.
294      */
295     public RulePriority getMinimumPriority() {
296         return minimumPriority;
297     }
298 
299     /**
300      * Set the minimum priority threshold when loading Rules from RuleSets.
301      * 
302      * @param minimumPriority
303      *            The minimum priority.
304      */
305     public void setMinimumPriority(RulePriority minimumPriority) {
306         this.minimumPriority = minimumPriority;
307     }
308 
309     /**
310      * Get the comma separated list of input paths to process for source files.
311      * 
312      * @return A comma separated list.
313      */
314     public String getInputPaths() {
315         return inputPaths;
316     }
317 
318     /**
319      * Set the comma separated list of input paths to process for source files.
320      * 
321      * @param inputPaths
322      *            The comma separated list.
323      */
324     public void setInputPaths(String inputPaths) {
325         this.inputPaths = inputPaths;
326     }
327 
328     /**
329      * Get the input URI to process for source code objects.
330      * 
331      * @return URI
332      */
333     public String getInputUri() {
334         return inputUri;
335     }
336 
337     /**
338      * Set the input URI to process for source code objects.
339      * 
340      * @param inputUri
341      *            a single URI
342      */
343     public void setInputUri(String inputUri) {
344         this.inputUri = inputUri;
345     }
346 
347     /**
348      * Get whether to use File short names in Reports.
349      * 
350      * @return <code>true</code> when using short names in reports.
351      */
352     public boolean isReportShortNames() {
353         return reportShortNames;
354     }
355 
356     /**
357      * Set whether to use File short names in Reports.
358      * 
359      * @param reportShortNames
360      *            <code>true</code> when using short names in reports.
361      */
362     public void setReportShortNames(boolean reportShortNames) {
363         this.reportShortNames = reportShortNames;
364     }
365 
366     /**
367      * Create a Renderer instance based upon the configured reporting options.
368      * No writer is created.
369      * 
370      * @return renderer
371      */
372     public Renderer createRenderer() {
373         return createRenderer(false);
374     }
375 
376     /**
377      * Create a Renderer instance based upon the configured reporting options.
378      * If withReportWriter then we'll configure it with a writer for the
379      * reportFile specified.
380      * 
381      * @param withReportWriter whether to configure a writer or not
382      * @return A Renderer instance.
383      */
384     public Renderer createRenderer(boolean withReportWriter) {
385         Renderer renderer = RendererFactory.createRenderer(reportFormat, reportProperties);
386         renderer.setShowSuppressedViolations(showSuppressedViolations);
387         if (withReportWriter) {
388             renderer.setWriter(IOUtil.createWriter(reportFile));
389         }
390         return renderer;
391     }
392 
393     /**
394      * Get the report format.
395      * 
396      * @return The report format.
397      */
398     public String getReportFormat() {
399         return reportFormat;
400     }
401 
402     /**
403      * Set the report format. This should be a name of a Renderer.
404      * 
405      * @param reportFormat
406      *            The report format.
407      * 
408      * @see Renderer
409      */
410     public void setReportFormat(String reportFormat) {
411         this.reportFormat = reportFormat;
412     }
413 
414     /**
415      * Get the file to which the report should render.
416      * 
417      * @return The file to which to render.
418      */
419     public String getReportFile() {
420         return reportFile;
421     }
422 
423     /**
424      * Set the file to which the report should render.
425      * 
426      * @param reportFile the file to set
427      */
428     public void setReportFile(String reportFile) {
429         this.reportFile = reportFile;
430     }
431 
432     /**
433      * Get whether the report should show suppressed violations.
434      * 
435      * @return <code>true</code> if showing suppressed violations,
436      *         <code>false</code> otherwise.
437      */
438     public boolean isShowSuppressedViolations() {
439         return showSuppressedViolations;
440     }
441 
442     /**
443      * Set whether the report should show suppressed violations.
444      * 
445      * @param showSuppressedViolations
446      *            <code>true</code> if showing suppressed violations,
447      *            <code>false</code> otherwise.
448      */
449     public void setShowSuppressedViolations(boolean showSuppressedViolations) {
450         this.showSuppressedViolations = showSuppressedViolations;
451     }
452 
453     /**
454      * Get the Report properties. These are used to create the Renderer.
455      * 
456      * @return The report properties.
457      */
458     public Properties getReportProperties() {
459         return reportProperties;
460     }
461 
462     /**
463      * Set the Report properties. These are used to create the Renderer.
464      * 
465      * @param reportProperties
466      *            The Report properties to set.
467      */
468     public void setReportProperties(Properties reportProperties) {
469         this.reportProperties = reportProperties;
470     }
471 
472     /**
473      * Return the stress test indicator. If this value is <code>true</code> then
474      * PMD will randomize the order of file processing to attempt to shake out
475      * bugs.
476      * 
477      * @return <code>true</code> if stress test is enbaled, <code>false</code>
478      *         otherwise.
479      */
480     public boolean isStressTest() {
481         return stressTest;
482     }
483 
484     /**
485      * Set the stress test indicator.
486      * 
487      * @param stressTest
488      *            The stree test indicator to set.
489      * @see #isStressTest()
490      */
491     public void setStressTest(boolean stressTest) {
492         this.stressTest = stressTest;
493     }
494 
495     /**
496      * Return the benchmark indicator. If this value is <code>true</code> then
497      * PMD will log benchmark information.
498      * 
499      * @return <code>true</code> if benchmark logging is enbaled,
500      *         <code>false</code> otherwise.
501      */
502     public boolean isBenchmark() {
503         return benchmark;
504     }
505 
506     /**
507      * Set the benchmark indicator.
508      * 
509      * @param benchmark
510      *            The benchmark indicator to set.
511      * @see #isBenchmark()
512      */
513     public void setBenchmark(boolean benchmark) {
514         this.benchmark = benchmark;
515     }
516 
517     /**
518      * Whether PMD should exit with status 4 (the default behavior, true) if violations
519      * are found or just with 0 (to not break the build, e.g.).
520      * @return failOnViolation
521      */
522     public boolean isFailOnViolation() {
523         return failOnViolation;
524     }
525 
526     /**
527      * Sets whether PMD should exit with status 4 (the default behavior, true) if violations
528      * are found or just with 0 (to not break the build, e.g.).
529      * @param failOnViolation failOnViolation
530      */
531     public void setFailOnViolation(boolean failOnViolation) {
532         this.failOnViolation = failOnViolation;
533     }
534 }