View Javadoc

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 }