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 }