diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java b/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java index fec5ae5893..31aabbdc4e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java @@ -358,16 +358,18 @@ public class PMD { // Make sure the cache is listening for analysis results ctx.getReport().addListener(configuration.getAnalysisCache()); - + + final RuleSetFactory silentFactoy = new RuleSetFactory(ruleSetFactory, false); + /* * Check if multithreaded support is available. ExecutorService can also * be disabled if threadCount is not positive, e.g. using the * "-threads 0" command line option. */ if (configuration.getThreads() > 0) { - new MultiThreadProcessor(configuration).processFiles(ruleSetFactory, files, ctx, renderers); + new MultiThreadProcessor(configuration).processFiles(silentFactoy, files, ctx, renderers); } else { - new MonoThreadProcessor(configuration).processFiles(ruleSetFactory, files, ctx, renderers); + new MonoThreadProcessor(configuration).processFiles(silentFactoy, files, ctx, renderers); } // Persist the analysis cache diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java index b3fb50ec2c..db05119414 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java @@ -57,53 +57,43 @@ public class RuleSetFactory { private static final String MESSAGE = "message"; private static final String EXTERNAL_INFO_URL = "externalInfoUrl"; - private ClassLoader classLoader = RuleSetFactory.class.getClassLoader(); - private RulePriority minimumPriority = RulePriority.LOW; - private boolean warnDeprecated = false; - private RuleSetFactoryCompatibility compatibilityFilter = new RuleSetFactoryCompatibility(); + private final ClassLoader classLoader; + private final RulePriority minimumPriority; + private final boolean warnDeprecated; + private final RuleSetFactoryCompatibility compatibilityFilter; - /** - * Set the ClassLoader to use when loading Rules. - * - * @param classLoader The ClassLoader to use. - */ - public void setClassLoader(ClassLoader classLoader) { + public RuleSetFactory() { + this(RuleSetFactory.class.getClassLoader(), RulePriority.LOW, false, true); + } + + public RuleSetFactory(final ClassLoader classLoader, final RulePriority minimumPriority, + final boolean warnDeprecated, final boolean enableCompatibility) { this.classLoader = classLoader; - } - - /** - * Set the minimum rule priority threshold for all Rules which are loaded - * from RuleSets via reference. - * - * @param minimumPriority The minimum priority. - */ - public void setMinimumPriority(RulePriority minimumPriority) { this.minimumPriority = minimumPriority; - } - - /** - * Set whether warning messages should be logged for usage of deprecated - * Rules. - * - * @param warnDeprecated true to log warning messages. - */ - public void setWarnDeprecated(boolean warnDeprecated) { this.warnDeprecated = warnDeprecated; + + if (enableCompatibility) { + this.compatibilityFilter = new RuleSetFactoryCompatibility(); + } else { + this.compatibilityFilter = null; + } } - + /** - * Disable the ruleset compatibility filter. Disabling this filter will cause - * exception when loading a ruleset, which uses references to old/not existing rules. + * Constructor copying all configuration from another factory. + * @param factory The factory whose configuration to copy. + * @param warnDeprecated Whether deprecation warnings are to be produced by this factory. */ - public void disableCompatibilityFilter() { - compatibilityFilter = null; + public RuleSetFactory(final RuleSetFactory factory, final boolean warnDeprecated) { + this(factory.classLoader, factory.minimumPriority, + warnDeprecated, factory.compatibilityFilter != null); } /** * Gets the compatibility filter in order to adjust it, e.g. add additional filters. * @return the {@link RuleSetFactoryCompatibility} */ - public RuleSetFactoryCompatibility getCompatibilityFilter() { + /* package */ RuleSetFactoryCompatibility getCompatibilityFilter() { return compatibilityFilter; } @@ -143,7 +133,7 @@ public class RuleSetFactory { * @return The new RuleSets. * @throws RuleSetNotFoundException if unable to find a resource. */ - public synchronized RuleSets createRuleSets(String referenceString) throws RuleSetNotFoundException { + public RuleSets createRuleSets(String referenceString) throws RuleSetNotFoundException { return createRuleSets(RuleSetReferenceId.parse(referenceString)); } @@ -156,7 +146,7 @@ public class RuleSetFactory { * @return The new RuleSets. * @throws RuleSetNotFoundException if unable to find a resource. */ - public synchronized RuleSets createRuleSets(List ruleSetReferenceIds) + public RuleSets createRuleSets(List ruleSetReferenceIds) throws RuleSetNotFoundException { RuleSets ruleSets = new RuleSets(); for (RuleSetReferenceId ruleSetReferenceId : ruleSetReferenceIds) { @@ -177,7 +167,7 @@ public class RuleSetFactory { * @return A new RuleSet. * @throws RuleSetNotFoundException if unable to find a resource. */ - public synchronized RuleSet createRuleSet(String referenceString) throws RuleSetNotFoundException { + public RuleSet createRuleSet(String referenceString) throws RuleSetNotFoundException { List references = RuleSetReferenceId.parse(referenceString); if (references.isEmpty()) { throw new RuleSetNotFoundException("No RuleSetReferenceId can be parsed from the string: <" @@ -195,11 +185,11 @@ public class RuleSetFactory { * @return A new RuleSet. * @throws RuleSetNotFoundException if unable to find a resource. */ - public synchronized RuleSet createRuleSet(RuleSetReferenceId ruleSetReferenceId) throws RuleSetNotFoundException { + public RuleSet createRuleSet(RuleSetReferenceId ruleSetReferenceId) throws RuleSetNotFoundException { return createRuleSet(ruleSetReferenceId, false); } - private synchronized RuleSet createRuleSet(RuleSetReferenceId ruleSetReferenceId, + private RuleSet createRuleSet(RuleSetReferenceId ruleSetReferenceId, boolean withDeprecatedRuleReferences) throws RuleSetNotFoundException { return parseRuleSetNode(ruleSetReferenceId, withDeprecatedRuleReferences); } @@ -359,13 +349,11 @@ public class RuleSetFactory { } } - RuleSetFactory ruleSetFactory = new RuleSetFactory(); - ruleSetFactory.setClassLoader(classLoader); + RuleSetFactory ruleSetFactory = new RuleSetFactory(this, warnDeprecated); RuleSet otherRuleSet = ruleSetFactory.createRuleSet(RuleSetReferenceId.parse(ref).get(0)); for (Rule rule : otherRuleSet.getRules()) { excludedRulesCheck.remove(rule.getName()); - if (!ruleSetReference.getExcludes().contains(rule.getName()) - && rule.getPriority().compareTo(minimumPriority) <= 0 && !rule.isDeprecated()) { + if (!ruleSetReference.getExcludes().contains(rule.getName()) && !rule.isDeprecated()) { RuleReference ruleReference = new RuleReference(); ruleReference.setRuleSetReference(ruleSetReference); ruleReference.setRule(rule); @@ -530,8 +518,7 @@ public class RuleSetFactory { return; } - RuleSetFactory ruleSetFactory = new RuleSetFactory(); - ruleSetFactory.setClassLoader(classLoader); + RuleSetFactory ruleSetFactory = new RuleSetFactory(this, warnDeprecated); boolean isSameRuleSet = false; RuleSetReferenceId otherRuleSetReferenceId = RuleSetReferenceId.parse(ref).get(0); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RulesetsFactoryUtils.java b/pmd-core/src/main/java/net/sourceforge/pmd/RulesetsFactoryUtils.java index 7a13d8fe8f..e7ff72e315 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RulesetsFactoryUtils.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RulesetsFactoryUtils.java @@ -27,9 +27,7 @@ public final class RulesetsFactoryUtils { public static RuleSets getRuleSets(String rulesets, RuleSetFactory factory) { RuleSets ruleSets = null; try { - factory.setWarnDeprecated(true); ruleSets = factory.createRuleSets(rulesets); - factory.setWarnDeprecated(false); printRuleNamesInDebug(ruleSets); if (ruleSets.ruleCount() == 0) { String msg = "No rules found. Maybe you mispelled a rule name? (" + rulesets + ")"; @@ -64,13 +62,12 @@ public final class RulesetsFactoryUtils { return ruleSets; } - public static RuleSetFactory getRulesetFactory(PMDConfiguration configuration) { - RuleSetFactory ruleSetFactory = new RuleSetFactory(); - ruleSetFactory.setMinimumPriority(configuration.getMinimumPriority()); - if (!configuration.isRuleSetFactoryCompatibilityEnabled()) { - ruleSetFactory.disableCompatibilityFilter(); - } - return ruleSetFactory; + public static RuleSetFactory getRulesetFactory(final PMDConfiguration configuration) { + return new RuleSetFactory( + configuration.getClassLoader(), + configuration.getMinimumPriority(), + true, + configuration.isRuleSetFactoryCompatibilityEnabled()); } /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java b/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java index c758aee43e..20d133b0f6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java @@ -33,6 +33,7 @@ import net.sourceforge.pmd.RuleSet; import net.sourceforge.pmd.RuleSetFactory; import net.sourceforge.pmd.RuleSetNotFoundException; import net.sourceforge.pmd.RuleSets; +import net.sourceforge.pmd.RulesetsFactoryUtils; import net.sourceforge.pmd.ant.Formatter; import net.sourceforge.pmd.ant.PMDTask; import net.sourceforge.pmd.ant.SourceLanguage; @@ -102,23 +103,15 @@ public class PMDTaskImpl { setupClassLoader(); // Setup RuleSetFactory and validate RuleSets - RuleSetFactory ruleSetFactory = new RuleSetFactory(); - ruleSetFactory.setClassLoader(configuration.getClassLoader()); - if (!configuration.isRuleSetFactoryCompatibilityEnabled()) { - ruleSetFactory.disableCompatibilityFilter(); - } + RuleSetFactory ruleSetFactory = RulesetsFactoryUtils.getRulesetFactory(configuration); try { - // This is just used to validate and display rules. Each thread will - // create its own ruleset - ruleSetFactory.setMinimumPriority(configuration.getMinimumPriority()); - ruleSetFactory.setWarnDeprecated(true); + // This is just used to validate and display rules. Each thread will create its own ruleset String ruleSets = configuration.getRuleSets(); if (StringUtil.isNotEmpty(ruleSets)) { // Substitute env variables/properties configuration.setRuleSets(project.replaceProperties(ruleSets)); } RuleSets rules = ruleSetFactory.createRuleSets(configuration.getRuleSets()); - ruleSetFactory.setWarnDeprecated(false); logRulesUsed(rules); } catch (RuleSetNotFoundException e) { throw new BuildException(e.getMessage(), e); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/Benchmarker.java b/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/Benchmarker.java index 3586451e8b..21ce4aea4c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/Benchmarker.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/Benchmarker.java @@ -20,6 +20,7 @@ import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.PMDException; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RulePriority; import net.sourceforge.pmd.RuleSet; import net.sourceforge.pmd.RuleSetFactory; import net.sourceforge.pmd.RuleSetNotFoundException; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/processor/MultiThreadProcessor.java b/pmd-core/src/main/java/net/sourceforge/pmd/processor/MultiThreadProcessor.java index 157beda4f5..980d83829a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/processor/MultiThreadProcessor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/processor/MultiThreadProcessor.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.processor; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdThreadFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdThreadFactory.java index 1086124cb0..92d2649554 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdThreadFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdThreadFactory.java @@ -3,9 +3,6 @@ */ package net.sourceforge.pmd.processor; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; @@ -17,7 +14,6 @@ public class PmdThreadFactory implements ThreadFactory { private final RuleSetFactory ruleSetFactory; private final RuleContext ctx; private final AtomicInteger counter = new AtomicInteger(); - public List threadList = Collections.synchronizedList(new LinkedList()); public PmdThreadFactory(RuleSetFactory ruleSetFactory, RuleContext ctx) { this.ruleSetFactory = ruleSetFactory; @@ -27,7 +23,6 @@ public class PmdThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread t = PmdRunnable.createThread(counter.incrementAndGet(), r, ruleSetFactory, ctx); - threadList.add(t); return t; } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java index 412c56dbb0..0fbe28c557 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java @@ -342,9 +342,8 @@ public class RuleSetFactoryTest { @Test public void testReferencePriority() throws RuleSetNotFoundException { - RuleSetFactory rsf = new RuleSetFactory(); + RuleSetFactory rsf = new RuleSetFactory(getClass().getClassLoader(), RulePriority.LOW, false, true); - rsf.setMinimumPriority(RulePriority.LOW); RuleSet ruleSet = rsf .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_INTERNAL_CHAIN)); assertEquals("Number of Rules", 3, ruleSet.getRules().size()); @@ -352,20 +351,20 @@ public class RuleSetFactoryTest { assertNotNull(ruleSet.getRuleByName("MockRuleNameRef")); assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef")); - rsf.setMinimumPriority(RulePriority.MEDIUM_HIGH); + rsf = new RuleSetFactory(getClass().getClassLoader(), RulePriority.MEDIUM_HIGH, false, true); ruleSet = rsf .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_INTERNAL_CHAIN)); assertEquals("Number of Rules", 2, ruleSet.getRules().size()); assertNotNull(ruleSet.getRuleByName("MockRuleNameRef")); assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef")); - rsf.setMinimumPriority(RulePriority.HIGH); + rsf = new RuleSetFactory(getClass().getClassLoader(), RulePriority.HIGH, false, true); ruleSet = rsf .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_INTERNAL_CHAIN)); assertEquals("Number of Rules", 1, ruleSet.getRules().size()); assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef")); - rsf.setMinimumPriority(RulePriority.LOW); + rsf = new RuleSetFactory(getClass().getClassLoader(), RulePriority.LOW, false, true); ruleSet = rsf .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_EXTERNAL_CHAIN)); assertEquals("Number of Rules", 3, ruleSet.getRules().size()); @@ -373,14 +372,14 @@ public class RuleSetFactoryTest { assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRef")); assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef")); - rsf.setMinimumPriority(RulePriority.MEDIUM_HIGH); + rsf = new RuleSetFactory(getClass().getClassLoader(), RulePriority.MEDIUM_HIGH, false, true); ruleSet = rsf .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_EXTERNAL_CHAIN)); assertEquals("Number of Rules", 2, ruleSet.getRules().size()); assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRef")); assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef")); - rsf.setMinimumPriority(RulePriority.HIGH); + rsf = new RuleSetFactory(getClass().getClassLoader(), RulePriority.HIGH, false, true); ruleSet = rsf .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_EXTERNAL_CHAIN)); assertEquals("Number of Rules", 1, ruleSet.getRules().size()); @@ -407,11 +406,10 @@ public class RuleSetFactoryTest { @Test public void testSetPriority() throws RuleSetNotFoundException { - RuleSetFactory rsf = new RuleSetFactory(); - rsf.setMinimumPriority(RulePriority.MEDIUM_HIGH); + RuleSetFactory rsf = new RuleSetFactory(getClass().getClassLoader(), RulePriority.MEDIUM_HIGH, false, true); assertEquals(0, rsf .createRuleSet(createRuleSetReferenceId(SINGLE_RULE)).size()); - rsf.setMinimumPriority(RulePriority.MEDIUM_LOW); + rsf = new RuleSetFactory(getClass().getClassLoader(), RulePriority.MEDIUM_LOW, false, true); assertEquals(1, rsf .createRuleSet(createRuleSetReferenceId(SINGLE_RULE)).size()); } diff --git a/src/site/markdown/overview/changelog.md b/src/site/markdown/overview/changelog.md index a6e8f97aa1..7cf1ed2246 100644 --- a/src/site/markdown/overview/changelog.md +++ b/src/site/markdown/overview/changelog.md @@ -36,6 +36,7 @@ * [#128](https://github.com/pmd/pmd/pull/128): \[java] Minor optimizations to type resolution * [#129](https://github.com/pmd/pmd/pull/129): \[plsql] Added correct parse of IS [NOT] NULL and multiline DML * [#130](https://github.com/pmd/pmd/pull/130); \[core] Reduce thread contention +* [#131](https://github.com/pmd/pmd/pull/131): \[core] Make RuleSetFactory immutable * [#135](https://github.com/pmd/pmd/pull/135): \[apex] New ruleset for Apex security **Bugfixes:**