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 }