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