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 RulePriority minimumPriority = RulePriority.LOW;
95      private String inputPaths;
96      private String inputUri;
97  
98      // Reporting options
99      private String reportFormat;
100     private String reportFile;
101     private boolean reportShortNames = false;
102     private Properties reportProperties = new Properties();
103     private boolean showSuppressedViolations = false;
104 
105     private boolean stressTest;
106     private boolean benchmark;
107 
108     /**
109      * Get the suppress marker. This is the source level marker used to indicate a
110      * RuleViolation should be suppressed.
111      * 
112      * @return The suppress marker.
113      */
114     public String getSuppressMarker() {
115         return suppressMarker;
116     }
117 
118     /**
119      * Set the suppress marker.
120      * 
121      * @param suppressMarker
122      *            The suppress marker to use.
123      */
124     public void setSuppressMarker(String suppressMarker) {
125         this.suppressMarker = suppressMarker;
126     }
127 
128     /**
129      * Get the number of threads to use when processing Rules.
130      * 
131      * @return The number of threads.
132      */
133     public int getThreads() {
134         return threads;
135     }
136 
137     /**
138      * Set the number of threads to use when processing Rules.
139      * 
140      * @param threads
141      *            The number of threads.
142      */
143     public void setThreads(int threads) {
144         this.threads = threads;
145     }
146 
147     /**
148      * Get the ClassLoader being used by PMD when processing Rules.
149      * 
150      * @return The ClassLoader being used
151      */
152     public ClassLoader getClassLoader() {
153         return classLoader;
154     }
155 
156     /**
157      * Set the ClassLoader being used by PMD when processing Rules. Setting a
158      * value of <code>null</code> will cause the default ClassLoader to be used.
159      * 
160      * @param classLoader
161      *            The ClassLoader to use
162      */
163     public void setClassLoader(ClassLoader classLoader) {
164         if (classLoader == null) {
165             this.classLoader = getClass().getClassLoader();
166         } else {
167             this.classLoader = classLoader;
168         }
169     }
170 
171     /**
172      * Prepend the specified classpath like string to the current ClassLoader of
173      * the configuration. If no ClassLoader is currently configured, the
174      * ClassLoader used to load the {@link PMDConfiguration} class will be used
175      * as the parent ClassLoader of the created ClassLoader.
176      * <p>
177      * If the classpath String looks like a URL to a file (i.e. starts with
178      * <code>file://</code>) the file will be read with each line representing
179      * an entry on the classpath.
180      * 
181      * @param classpath The prepended classpath.
182      * @throws IOException if the given classpath is invalid (e.g. does not exist)
183      * @see PMDConfiguration#setClassLoader(ClassLoader)
184      * @see ClasspathClassLoader
185      */
186     public void prependClasspath(String classpath) throws IOException {
187         if (classLoader == null) {
188             classLoader = PMDConfiguration.class.getClassLoader();
189         }
190         if (classpath != null) {
191             classLoader = new ClasspathClassLoader(classpath, classLoader);
192         }
193     }
194 
195     /**
196      * Get the LanguageVersionDiscoverer, used to determine the LanguageVersion
197      * of a source file.
198      * 
199      * @return The LanguageVersionDiscoverer.
200      */
201     public LanguageVersionDiscoverer getLanguageVersionDiscoverer() {
202         return languageVersionDiscoverer;
203     }
204 
205     /**
206      * Set the given LanguageVersion as the current default for it's Language.
207      * 
208      * @param languageVersion
209      *            the LanguageVersion
210      */
211     public void setDefaultLanguageVersion(LanguageVersion languageVersion) {
212         setDefaultLanguageVersions(Arrays.asList(languageVersion));
213     }
214 
215     /**
216      * Set the given LanguageVersions as the current default for their
217      * Languages.
218      * 
219      * @param languageVersions
220      *            The LanguageVersions.
221      */
222     public void setDefaultLanguageVersions(List<LanguageVersion> languageVersions) {
223         for (LanguageVersion languageVersion : languageVersions) {
224             languageVersionDiscoverer.setDefaultLanguageVersion(languageVersion);
225         }
226     }
227 
228     /**
229      * Get the LanguageVersion of the source file with given name. This depends
230      * on the fileName extension, and the java version.
231      * <p/>
232      * For compatibility with older code that does not always pass in a correct
233      * filename, unrecognized files are assumed to be java files.
234      * 
235      * @param fileName
236      *            Name of the file, can be absolute, or simple.
237      * @return the LanguageVersion
238      */
239     // FUTURE Delete this? I can't think of a good reason to keep it around.
240     // Failure to determine the LanguageVersion for a file should be a hard
241     // error, or simply cause the file to be skipped?
242     public LanguageVersion getLanguageVersionOfFile(String fileName) {
243         LanguageVersion languageVersion = languageVersionDiscoverer.getDefaultLanguageVersionForFile(fileName);
244         if (languageVersion == null) {
245             // For compatibility with older code that does not always pass in
246             // a correct filename.
247             languageVersion = languageVersionDiscoverer.getDefaultLanguageVersion(LanguageRegistry.getLanguage("Java"));
248         }
249         return languageVersion;
250     }
251 
252     /**
253      * Get the comma separated list of RuleSet URIs.
254      * 
255      * @return The RuleSet URIs.
256      */
257     public String getRuleSets() {
258         return ruleSets;
259     }
260 
261     /**
262      * Set the comma separated list of RuleSet URIs.
263      * 
264      * @param ruleSets the rulesets to set
265      */
266     public void setRuleSets(String ruleSets) {
267         this.ruleSets = ruleSets;
268     }
269 
270     /**
271      * Get the minimum priority threshold when loading Rules from RuleSets.
272      * 
273      * @return The minimum priority threshold.
274      */
275     public RulePriority getMinimumPriority() {
276         return minimumPriority;
277     }
278 
279     /**
280      * Set the minimum priority threshold when loading Rules from RuleSets.
281      * 
282      * @param minimumPriority
283      *            The minimum priority.
284      */
285     public void setMinimumPriority(RulePriority minimumPriority) {
286         this.minimumPriority = minimumPriority;
287     }
288 
289     /**
290      * Get the comma separated list of input paths to process for source files.
291      * 
292      * @return A comma separated list.
293      */
294     public String getInputPaths() {
295         return inputPaths;
296     }
297 
298     /**
299      * Set the comma separated list of input paths to process for source files.
300      * 
301      * @param inputPaths
302      *            The comma separated list.
303      */
304     public void setInputPaths(String inputPaths) {
305         this.inputPaths = inputPaths;
306     }
307 
308     /**
309      * Get the input URI to process for source code objects.
310      * 
311      * @return URI
312      */
313     public String getInputUri() {
314         return inputUri;
315     }
316 
317     /**
318      * Set the input URI to process for source code objects.
319      * 
320      * @param inputUri
321      *            a single URI
322      */
323     public void setInputUri(String inputUri) {
324         this.inputUri = inputUri;
325     }
326 
327     /**
328      * Get whether to use File short names in Reports.
329      * 
330      * @return <code>true</code> when using short names in reports.
331      */
332     public boolean isReportShortNames() {
333         return reportShortNames;
334     }
335 
336     /**
337      * Set whether to use File short names in Reports.
338      * 
339      * @param reportShortNames
340      *            <code>true</code> when using short names in reports.
341      */
342     public void setReportShortNames(boolean reportShortNames) {
343         this.reportShortNames = reportShortNames;
344     }
345 
346     /**
347      * Create a Renderer instance based upon the configured reporting options.
348      * No writer is created.
349      * 
350      * @return renderer
351      */
352     public Renderer createRenderer() {
353         return createRenderer(false);
354     }
355 
356     /**
357      * Create a Renderer instance based upon the configured reporting options.
358      * If withReportWriter then we'll configure it with a writer for the
359      * reportFile specified.
360      * 
361      * @param withReportWriter whether to configure a writer or not
362      * @return A Renderer instance.
363      */
364     public Renderer createRenderer(boolean withReportWriter) {
365         Renderer renderer = RendererFactory.createRenderer(reportFormat, reportProperties);
366         renderer.setShowSuppressedViolations(showSuppressedViolations);
367         if (withReportWriter) {
368             renderer.setWriter(IOUtil.createWriter(reportFile));
369         }
370         return renderer;
371     }
372 
373     /**
374      * Get the report format.
375      * 
376      * @return The report format.
377      */
378     public String getReportFormat() {
379         return reportFormat;
380     }
381 
382     /**
383      * Set the report format. This should be a name of a Renderer.
384      * 
385      * @param reportFormat
386      *            The report format.
387      * 
388      * @see Renderer
389      */
390     public void setReportFormat(String reportFormat) {
391         this.reportFormat = reportFormat;
392     }
393 
394     /**
395      * Get the file to which the report should render.
396      * 
397      * @return The file to which to render.
398      */
399     public String getReportFile() {
400         return reportFile;
401     }
402 
403     /**
404      * Set the file to which the report should render.
405      * 
406      * @param reportFile the file to set
407      */
408     public void setReportFile(String reportFile) {
409         this.reportFile = reportFile;
410     }
411 
412     /**
413      * Get whether the report should show suppressed violations.
414      * 
415      * @return <code>true</code> if showing suppressed violations,
416      *         <code>false</code> otherwise.
417      */
418     public boolean isShowSuppressedViolations() {
419         return showSuppressedViolations;
420     }
421 
422     /**
423      * Set whether the report should show suppressed violations.
424      * 
425      * @param showSuppressedViolations
426      *            <code>true</code> if showing suppressed violations,
427      *            <code>false</code> otherwise.
428      */
429     public void setShowSuppressedViolations(boolean showSuppressedViolations) {
430         this.showSuppressedViolations = showSuppressedViolations;
431     }
432 
433     /**
434      * Get the Report properties. These are used to create the Renderer.
435      * 
436      * @return The report properties.
437      */
438     public Properties getReportProperties() {
439         return reportProperties;
440     }
441 
442     /**
443      * Set the Report properties. These are used to create the Renderer.
444      * 
445      * @param reportProperties
446      *            The Report properties to set.
447      */
448     public void setReportProperties(Properties reportProperties) {
449         this.reportProperties = reportProperties;
450     }
451 
452     /**
453      * Return the stress test indicator. If this value is <code>true</code> then
454      * PMD will randomize the order of file processing to attempt to shake out
455      * bugs.
456      * 
457      * @return <code>true</code> if stress test is enbaled, <code>false</code>
458      *         otherwise.
459      */
460     public boolean isStressTest() {
461         return stressTest;
462     }
463 
464     /**
465      * Set the stress test indicator.
466      * 
467      * @param stressTest
468      *            The stree test indicator to set.
469      * @see #isStressTest()
470      */
471     public void setStressTest(boolean stressTest) {
472         this.stressTest = stressTest;
473     }
474 
475     /**
476      * Return the benchmark indicator. If this value is <code>true</code> then
477      * PMD will log benchmark information.
478      * 
479      * @return <code>true</code> if benchmark logging is enbaled,
480      *         <code>false</code> otherwise.
481      */
482     public boolean isBenchmark() {
483         return benchmark;
484     }
485 
486     /**
487      * Set the benchmark indicator.
488      * 
489      * @param benchmark
490      *            The benchmark indicator to set.
491      * @see #isBenchmark()
492      */
493     public void setBenchmark(boolean benchmark) {
494         this.benchmark = benchmark;
495     }
496 }