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.Language; 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 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(Language.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 return renderer; 370 } 371 372 /** 373 * Get the report format. 374 * 375 * @return The report format. 376 */ 377 public String getReportFormat() { 378 return reportFormat; 379 } 380 381 /** 382 * Set the report format. This should be a name of a Renderer. 383 * 384 * @param reportFormat 385 * The report format. 386 * 387 * @see Renderer 388 */ 389 public void setReportFormat(String reportFormat) { 390 this.reportFormat = reportFormat; 391 } 392 393 /** 394 * Get the file to which the report should render. 395 * 396 * @return The file to which to render. 397 */ 398 public String getReportFile() { 399 return reportFile; 400 } 401 402 /** 403 * Set the file to which the report should render. 404 * 405 * @param reportFile the file to set 406 */ 407 public void setReportFile(String reportFile) { 408 this.reportFile = reportFile; 409 } 410 411 /** 412 * Get whether the report should show suppressed violations. 413 * 414 * @return <code>true</code> if showing suppressed violations, 415 * <code>false</code> otherwise. 416 */ 417 public boolean isShowSuppressedViolations() { 418 return showSuppressedViolations; 419 } 420 421 /** 422 * Set whether the report should show suppressed violations. 423 * 424 * @param showSuppressedViolations 425 * <code>true</code> if showing suppressed violations, 426 * <code>false</code> otherwise. 427 */ 428 public void setShowSuppressedViolations(boolean showSuppressedViolations) { 429 this.showSuppressedViolations = showSuppressedViolations; 430 } 431 432 /** 433 * Get the Report properties. These are used to create the Renderer. 434 * 435 * @return The report properties. 436 */ 437 public Properties getReportProperties() { 438 return reportProperties; 439 } 440 441 /** 442 * Set the Report properties. These are used to create the Renderer. 443 * 444 * @param reportProperties 445 * The Report properties to set. 446 */ 447 public void setReportProperties(Properties reportProperties) { 448 this.reportProperties = reportProperties; 449 } 450 451 /** 452 * Return the stress test indicator. If this value is <code>true</code> then 453 * PMD will randomize the order of file processing to attempt to shake out 454 * bugs. 455 * 456 * @return <code>true</code> if stress test is enbaled, <code>false</code> 457 * otherwise. 458 */ 459 public boolean isStressTest() { 460 return stressTest; 461 } 462 463 /** 464 * Set the stress test indicator. 465 * 466 * @param stressTest 467 * The stree test indicator to set. 468 * @see #isStressTest() 469 */ 470 public void setStressTest(boolean stressTest) { 471 this.stressTest = stressTest; 472 } 473 474 /** 475 * Return the benchmark indicator. If this value is <code>true</code> then 476 * PMD will log benchmark information. 477 * 478 * @return <code>true</code> if benchmark logging is enbaled, 479 * <code>false</code> otherwise. 480 */ 481 public boolean isBenchmark() { 482 return benchmark; 483 } 484 485 /** 486 * Set the benchmark indicator. 487 * 488 * @param benchmark 489 * The benchmark indicator to set. 490 * @see #isBenchmark() 491 */ 492 public void setBenchmark(boolean benchmark) { 493 this.benchmark = benchmark; 494 } 495 }