/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Properties; import net.sourceforge.pmd.cache.AnalysisCache; import net.sourceforge.pmd.cache.FileAnalysisCache; import net.sourceforge.pmd.cache.NoopAnalysisCache; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.LanguageVersionDiscoverer; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.renderers.RendererFactory; import net.sourceforge.pmd.util.ClasspathClassLoader; import net.sourceforge.pmd.util.IOUtil; /** * This class contains the details for the runtime configuration of PMD. There * are several aspects to the configuration of PMD. * * <p>The aspects related to generic PMD behavior:</p> * <ul> * <li>Suppress marker is used in source files to suppress a RuleViolation, * defaults to {@link PMD#SUPPRESS_MARKER}. {@link #getSuppressMarker()}</li> * <li>The number of threads to create when invoking on multiple files, defaults * one thread per available processor. {@link #getThreads()}</li> * <li>A ClassLoader to use when loading classes during Rule processing (e.g. * during type resolution), defaults to ClassLoader of the Configuration class. * {@link #getClassLoader()}</li> * <li>A means to configure a ClassLoader using a prepended classpath String, * instead of directly setting it programmatically. * {@link #prependClasspath(String)}</li> * <li>A LanguageVersionDiscoverer instance, which defaults to using the default * LanguageVersion of each Language. Means are provided to change the * LanguageVersion for each Language. * {@link #getLanguageVersionDiscoverer()}</li> * </ul> * * <p>The aspects related to Rules and Source files are:</p> * <ul> * <li>A comma separated list of RuleSets URIs. {@link #getRuleSets()}</li> * <li>A minimum priority threshold when loading Rules from RuleSets, defaults * to {@link RulePriority#LOW}. {@link #getMinimumPriority()}</li> * <li>The character encoding of source files, defaults to the system default as * returned by <code>System.getProperty("file.encoding")</code>. * {@link #getSourceEncoding()}</li> * <li>A comma separated list of input paths to process for source files. This * may include files, directories, archives (e.g. ZIP files), etc. * {@link #getInputPaths()}</li> * <li>A flag which controls, whether {@link RuleSetFactoryCompatibility} filter * should be used or not: #isRuleSetFactoryCompatibilityEnabled; * </ul> * * <ul> * <li>The renderer format to use for Reports. {@link #getReportFormat()}</li> * <li>The file to which the Report should render. {@link #getReportFile()}</li> * <li>An indicator of whether to use File short names in Reports, defaults to * <code>false</code>. {@link #isReportShortNames()}</li> * <li>The initialization properties to use when creating a Renderer instance. * {@link #getReportProperties()}</li> * <li>An indicator of whether to show suppressed Rule violations in Reports. * {@link #isShowSuppressedViolations()}</li> * </ul> * * <p>The aspects related to special PMD behavior are:</p> * <ul> * <li>An indicator of whether PMD should log debug information. * {@link #isDebug()}</li> * <li>An indicator of whether PMD should perform stress testing behaviors, such * as randomizing the order of file processing. {@link #isStressTest()}</li> * <li>An indicator of whether PMD should log benchmarking information. * {@link #isBenchmark()}</li> * </ul> */ public class PMDConfiguration extends AbstractConfiguration { // General behavior options private String suppressMarker = PMD.SUPPRESS_MARKER; private int threads = Runtime.getRuntime().availableProcessors(); private ClassLoader classLoader = getClass().getClassLoader(); private LanguageVersionDiscoverer languageVersionDiscoverer = new LanguageVersionDiscoverer(); // Rule and source file options private String ruleSets; private RulePriority minimumPriority = RulePriority.LOW; private String inputPaths; private String inputUri; private String inputFilePath; private boolean ruleSetFactoryCompatibilityEnabled = true; // Reporting options private String reportFormat; private String reportFile; private boolean reportShortNames = false; private Properties reportProperties = new Properties(); private boolean showSuppressedViolations = false; private boolean failOnViolation = true; private boolean stressTest; private boolean benchmark; private AnalysisCache analysisCache = new NoopAnalysisCache(); /** * Get the suppress marker. This is the source level marker used to indicate * a RuleViolation should be suppressed. * * @return The suppress marker. */ public String getSuppressMarker() { return suppressMarker; } /** * Set the suppress marker. * * @param suppressMarker * The suppress marker to use. */ public void setSuppressMarker(String suppressMarker) { this.suppressMarker = suppressMarker; } /** * Get the number of threads to use when processing Rules. * * @return The number of threads. */ public int getThreads() { return threads; } /** * Set the number of threads to use when processing Rules. * * @param threads * The number of threads. */ public void setThreads(int threads) { this.threads = threads; } /** * Get the ClassLoader being used by PMD when processing Rules. * * @return The ClassLoader being used */ public ClassLoader getClassLoader() { return classLoader; } /** * Set the ClassLoader being used by PMD when processing Rules. Setting a * value of <code>null</code> will cause the default ClassLoader to be used. * * @param classLoader * The ClassLoader to use */ public void setClassLoader(ClassLoader classLoader) { if (classLoader == null) { this.classLoader = getClass().getClassLoader(); } else { this.classLoader = classLoader; } } /** * Prepend the specified classpath like string to the current ClassLoader of * the configuration. If no ClassLoader is currently configured, the * ClassLoader used to load the {@link PMDConfiguration} class will be used * as the parent ClassLoader of the created ClassLoader. * * <p>If the classpath String looks like a URL to a file (i.e. starts with * <code>file://</code>) the file will be read with each line representing * an entry on the classpath.</p> * * @param classpath * The prepended classpath. * @throws IOException * if the given classpath is invalid (e.g. does not exist) * @see PMDConfiguration#setClassLoader(ClassLoader) * @see ClasspathClassLoader */ public void prependClasspath(String classpath) throws IOException { if (classLoader == null) { classLoader = PMDConfiguration.class.getClassLoader(); } if (classpath != null) { classLoader = new ClasspathClassLoader(classpath, classLoader); } } /** * Get the LanguageVersionDiscoverer, used to determine the LanguageVersion * of a source file. * * @return The LanguageVersionDiscoverer. */ public LanguageVersionDiscoverer getLanguageVersionDiscoverer() { return languageVersionDiscoverer; } /** * Set the given LanguageVersion as the current default for it's Language. * * @param languageVersion * the LanguageVersion */ public void setDefaultLanguageVersion(LanguageVersion languageVersion) { setDefaultLanguageVersions(Arrays.asList(languageVersion)); } /** * Set the given LanguageVersions as the current default for their * Languages. * * @param languageVersions * The LanguageVersions. */ public void setDefaultLanguageVersions(List<LanguageVersion> languageVersions) { for (LanguageVersion languageVersion : languageVersions) { languageVersionDiscoverer.setDefaultLanguageVersion(languageVersion); } } /** * Get the LanguageVersion of the source file with given name. This depends * on the fileName extension, and the java version. * <p> * For compatibility with older code that does not always pass in a correct * filename, unrecognized files are assumed to be java files. * </p> * * @param fileName * Name of the file, can be absolute, or simple. * @return the LanguageVersion */ // 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? public LanguageVersion getLanguageVersionOfFile(String fileName) { LanguageVersion languageVersion = languageVersionDiscoverer.getDefaultLanguageVersionForFile(fileName); if (languageVersion == null) { // For compatibility with older code that does not always pass in // a correct filename. languageVersion = languageVersionDiscoverer.getDefaultLanguageVersion(LanguageRegistry.getLanguage("Java")); } return languageVersion; } /** * Get the comma separated list of RuleSet URIs. * * @return The RuleSet URIs. */ public String getRuleSets() { return ruleSets; } /** * Set the comma separated list of RuleSet URIs. * * @param ruleSets * the rulesets to set */ public void setRuleSets(String ruleSets) { this.ruleSets = ruleSets; } /** * Get the minimum priority threshold when loading Rules from RuleSets. * * @return The minimum priority threshold. */ public RulePriority getMinimumPriority() { return minimumPriority; } /** * Set the minimum priority threshold when loading Rules from RuleSets. * * @param minimumPriority * The minimum priority. */ public void setMinimumPriority(RulePriority minimumPriority) { this.minimumPriority = minimumPriority; } /** * Get the comma separated list of input paths to process for source files. * * @return A comma separated list. */ public String getInputPaths() { return inputPaths; } /** * Set the comma separated list of input paths to process for source files. * * @param inputPaths * The comma separated list. */ public void setInputPaths(String inputPaths) { this.inputPaths = inputPaths; } public String getInputFilePath() { return inputFilePath; } /** * The input file path points to a single file, which contains a * comma-separated list of source file names to process. * * @param inputFilePath * path to the file */ public void setInputFilePath(String inputFilePath) { this.inputFilePath = inputFilePath; } /** * Get the input URI to process for source code objects. * * @return URI */ public String getInputUri() { return inputUri; } /** * Set the input URI to process for source code objects. * * @param inputUri * a single URI */ public void setInputUri(String inputUri) { this.inputUri = inputUri; } /** * Get whether to use File short names in Reports. * * @return <code>true</code> when using short names in reports. */ public boolean isReportShortNames() { return reportShortNames; } /** * Set whether to use File short names in Reports. * * @param reportShortNames * <code>true</code> when using short names in reports. */ public void setReportShortNames(boolean reportShortNames) { this.reportShortNames = reportShortNames; } /** * Create a Renderer instance based upon the configured reporting options. * No writer is created. * * @return renderer */ public Renderer createRenderer() { return createRenderer(false); } /** * Create a Renderer instance based upon the configured reporting options. * If withReportWriter then we'll configure it with a writer for the * reportFile specified. * * @param withReportWriter * whether to configure a writer or not * @return A Renderer instance. */ public Renderer createRenderer(boolean withReportWriter) { Renderer renderer = RendererFactory.createRenderer(reportFormat, reportProperties); renderer.setShowSuppressedViolations(showSuppressedViolations); if (withReportWriter) { renderer.setWriter(IOUtil.createWriter(reportFile)); } return renderer; } /** * Get the report format. * * @return The report format. */ public String getReportFormat() { return reportFormat; } /** * Set the report format. This should be a name of a Renderer. * * @param reportFormat * The report format. * * @see Renderer */ public void setReportFormat(String reportFormat) { this.reportFormat = reportFormat; } /** * Get the file to which the report should render. * * @return The file to which to render. */ public String getReportFile() { return reportFile; } /** * Set the file to which the report should render. * * @param reportFile * the file to set */ public void setReportFile(String reportFile) { this.reportFile = reportFile; } /** * Get whether the report should show suppressed violations. * * @return <code>true</code> if showing suppressed violations, * <code>false</code> otherwise. */ public boolean isShowSuppressedViolations() { return showSuppressedViolations; } /** * Set whether the report should show suppressed violations. * * @param showSuppressedViolations * <code>true</code> if showing suppressed violations, * <code>false</code> otherwise. */ public void setShowSuppressedViolations(boolean showSuppressedViolations) { this.showSuppressedViolations = showSuppressedViolations; } /** * Get the Report properties. These are used to create the Renderer. * * @return The report properties. */ public Properties getReportProperties() { return reportProperties; } /** * Set the Report properties. These are used to create the Renderer. * * @param reportProperties * The Report properties to set. */ public void setReportProperties(Properties reportProperties) { this.reportProperties = reportProperties; } /** * Return the stress test indicator. If this value is <code>true</code> then * PMD will randomize the order of file processing to attempt to shake out * bugs. * * @return <code>true</code> if stress test is enbaled, <code>false</code> * otherwise. */ public boolean isStressTest() { return stressTest; } /** * Set the stress test indicator. * * @param stressTest * The stree test indicator to set. * @see #isStressTest() */ public void setStressTest(boolean stressTest) { this.stressTest = stressTest; } /** * Return the benchmark indicator. If this value is <code>true</code> then * PMD will log benchmark information. * * @return <code>true</code> if benchmark logging is enbaled, * <code>false</code> otherwise. */ public boolean isBenchmark() { return benchmark; } /** * Set the benchmark indicator. * * @param benchmark * The benchmark indicator to set. * @see #isBenchmark() */ public void setBenchmark(boolean benchmark) { this.benchmark = benchmark; } /** * Whether PMD should exit with status 4 (the default behavior, true) if * violations are found or just with 0 (to not break the build, e.g.). * * @return failOnViolation */ public boolean isFailOnViolation() { return failOnViolation; } /** * Sets whether PMD should exit with status 4 (the default behavior, true) * if violations are found or just with 0 (to not break the build, e.g.). * * @param failOnViolation * failOnViolation */ public void setFailOnViolation(boolean failOnViolation) { this.failOnViolation = failOnViolation; } /** * Checks if the rule set factory compatibility feature is enabled. * * @return true, if the rule set factory compatibility feature is enabled * * @see RuleSetFactoryCompatibility */ public boolean isRuleSetFactoryCompatibilityEnabled() { return ruleSetFactoryCompatibilityEnabled; } /** * Sets the rule set factory compatibility feature enabled/disabled. * * @param ruleSetFactoryCompatibilityEnabled * <code>true</code> if the feature should be enabled * * @see RuleSetFactoryCompatibility */ public void setRuleSetFactoryCompatibilityEnabled(boolean ruleSetFactoryCompatibilityEnabled) { this.ruleSetFactoryCompatibilityEnabled = ruleSetFactoryCompatibilityEnabled; } /** * Retrieves the currently used analysis cache. Will never be null. * * @return The currently used analysis cache. Never null. */ public AnalysisCache getAnalysisCache() { return analysisCache; } /** * Sets the analysis cache to be used. Setting a * value of <code>null</code> will cause a Noop AnalysisCache to be used. * * @param cache The analysis cache to be used. */ public void setAnalysisCache(final AnalysisCache cache) { if (cache == null) { analysisCache = new NoopAnalysisCache(); } else { analysisCache = cache; } } /** * Sets the location of the analysis cache to be used. This will automatically configure * and appropriate AnalysisCache implementation. * * @param cacheLocation The location of the analysis cache to be used. */ public void setAnalysisCacheLocation(final String cacheLocation) { if (cacheLocation == null) { setAnalysisCache(new NoopAnalysisCache()); } else { setAnalysisCache(new FileAnalysisCache(new File(cacheLocation))); } } }