[core] RuleSetFactory: Filter by minimumPriority at the end

-   Resolves #394
This commit is contained in:
Andreas Dangel
2017-11-11 11:37:45 +01:00
parent c647f73811
commit ba3e2bc788
6 changed files with 110 additions and 19 deletions

View File

@ -122,15 +122,24 @@ public class RuleSet implements ChecksumAware {
* Add a new rule to this ruleset. Note that this method does not check * Add a new rule to this ruleset. Note that this method does not check
* for duplicates. * for duplicates.
* *
* @param rule * @param newRule
* the rule to be added * the rule to be added
* @return The same builder, for a fluid programming interface * @return The same builder, for a fluid programming interface
*/ */
public RuleSetBuilder addRule(final Rule rule) { public RuleSetBuilder addRule(final Rule newRule) {
if (rule == null) { if (newRule == null) {
throw new IllegalArgumentException(MISSING_RULE); throw new IllegalArgumentException(MISSING_RULE);
} }
rules.add(rule);
// check for duplicates - adding more than one rule with the same name will
// be problematic - see #RuleSet.getRuleByName(String)
for (Rule rule : rules) {
if (rule.getName().equals(newRule.getName()) && rule.getLanguage() == newRule.getLanguage()) {
LOG.warning("Duplicated rule: " + newRule.getName());
}
}
rules.add(newRule);
return this; return this;
} }
@ -387,6 +396,17 @@ public class RuleSet implements ChecksumAware {
public RuleSet build() { public RuleSet build() {
return new RuleSet(this); return new RuleSet(this);
} }
public void filterRulesByPriority(RulePriority minimumPriority) {
Iterator<Rule> iterator = rules.iterator();
while (iterator.hasNext()) {
Rule rule = iterator.next();
if (rule.getPriority().compareTo(minimumPriority) > 0) {
LOG.fine("Removing rule " + rule.getName() + " due to priority: " + rule.getPriority() + " required: " + minimumPriority);
iterator.remove();
}
}
}
} }
/** /**

View File

@ -380,6 +380,8 @@ public class RuleSetFactory {
ruleSetBuilder.withDescription("Missing description"); ruleSetBuilder.withDescription("Missing description");
} }
ruleSetBuilder.filterRulesByPriority(minimumPriority);
return ruleSetBuilder.build(); return ruleSetBuilder.build();
} catch (ClassNotFoundException cnfe) { } catch (ClassNotFoundException cnfe) {
return classNotFoundProblem(cnfe); return classNotFoundProblem(cnfe);
@ -496,7 +498,9 @@ public class RuleSetFactory {
} }
final RuleSetReference ruleSetReference = new RuleSetReference(ref, true, excludedRulesCheck); final RuleSetReference ruleSetReference = new RuleSetReference(ref, true, excludedRulesCheck);
RuleSetFactory ruleSetFactory = new RuleSetFactory(this, warnDeprecated); // load the ruleset with minimum priority low, so that we get all rules, to be able to exclude any rule
// minimum priority will be applied again, before constructing the final ruleset
RuleSetFactory ruleSetFactory = new RuleSetFactory(resourceLoader, RulePriority.LOW, warnDeprecated, this.compatibilityFilter != null);
RuleSet otherRuleSet = ruleSetFactory.createRuleSet(RuleSetReferenceId.parse(ref).get(0)); RuleSet otherRuleSet = ruleSetFactory.createRuleSet(RuleSetReferenceId.parse(ref).get(0));
for (Rule rule : otherRuleSet.getRules()) { for (Rule rule : otherRuleSet.getRules()) {
excludedRulesCheck.remove(rule.getName()); excludedRulesCheck.remove(rule.getName());
@ -504,12 +508,12 @@ public class RuleSetFactory {
RuleReference ruleReference = new RuleReference(); RuleReference ruleReference = new RuleReference();
ruleReference.setRuleSetReference(ruleSetReference); ruleReference.setRuleSetReference(ruleSetReference);
ruleReference.setRule(rule); ruleReference.setRule(rule);
ruleSetBuilder.addRuleIfNotExists(ruleReference);
// override the priority // override the priority
if (priority != null) { if (priority != null) {
ruleReference.setPriority(RulePriority.valueOf(Integer.parseInt(priority))); ruleReference.setPriority(RulePriority.valueOf(Integer.parseInt(priority)));
} }
ruleSetBuilder.addRuleIfNotExists(ruleReference);
} }
} }
if (!excludedRulesCheck.isEmpty()) { if (!excludedRulesCheck.isEmpty()) {
@ -639,12 +643,9 @@ public class RuleSetFactory {
throw new IllegalArgumentException(UNEXPECTED_ELEMENT + nodeName throw new IllegalArgumentException(UNEXPECTED_ELEMENT + nodeName
+ "> encountered as child of <rule> element for Rule " + rule.getName()); + "> encountered as child of <rule> element for Rule " + rule.getName());
} }
}
} ruleSetBuilder.addRule(rule);
if (StringUtils.isNotBlank(ruleSetReferenceId.getRuleName())
|| rule.getPriority().compareTo(minimumPriority) <= 0) {
ruleSetBuilder.addRule(rule);
}
} }
private static boolean hasAttributeSetTrue(Element element, String attributeId) { private static boolean hasAttributeSetTrue(Element element, String attributeId) {
@ -679,7 +680,9 @@ public class RuleSetFactory {
return; return;
} }
RuleSetFactory ruleSetFactory = new RuleSetFactory(this, warnDeprecated); // load the ruleset with minimum priority low, so that we get all rules, to be able to exclude any rule
// minimum priority will be applied again, before constructing the final ruleset
RuleSetFactory ruleSetFactory = new RuleSetFactory(resourceLoader, RulePriority.LOW, warnDeprecated, this.compatibilityFilter != null);
boolean isSameRuleSet = false; boolean isSameRuleSet = false;
RuleSetReferenceId otherRuleSetReferenceId = RuleSetReferenceId.parse(ref).get(0); RuleSetReferenceId otherRuleSetReferenceId = RuleSetReferenceId.parse(ref).get(0);
@ -756,11 +759,8 @@ public class RuleSetFactory {
} }
} }
if (StringUtils.isNotBlank(ruleSetReferenceId.getRuleName()) if (withDeprecatedRuleReferences || !isSameRuleSet || !ruleReference.isDeprecated()) {
|| referencedRule.getPriority().compareTo(minimumPriority) <= 0) { ruleSetBuilder.addRuleReplaceIfExists(ruleReference);
if (withDeprecatedRuleReferences || !isSameRuleSet || !ruleReference.isDeprecated()) {
ruleSetBuilder.addRuleReplaceIfExists(ruleReference);
}
} }
} }

View File

@ -363,6 +363,45 @@ public class RuleSetFactoryTest {
assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef")); assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef"));
} }
@Test
public void testOverridePriorityLoadWithMinimum() throws RuleSetNotFoundException {
RuleSetFactory rsf = new RuleSetFactory(new ResourceLoader(), RulePriority.MEDIUM_LOW, true, true);
RuleSet ruleset = rsf.createRuleSet("net/sourceforge/pmd/rulesets/ruleset-minimum-priority.xml");
// only one rule should remain, since we filter out the other rules by minimum priority
assertEquals("Number of Rules", 1, ruleset.getRules().size());
// Priority is overridden and applied, rule is missing
assertNull(ruleset.getRuleByName("DummyBasicMockRule"));
// that's the remaining rule
assertNotNull(ruleset.getRuleByName("SampleXPathRule"));
// now, load with default minimum priority
rsf = new RuleSetFactory();
ruleset = rsf.createRuleSet("net/sourceforge/pmd/rulesets/ruleset-minimum-priority.xml");
assertEquals("Number of Rules", 2, ruleset.getRules().size());
Rule dummyBasicMockRule = ruleset.getRuleByName("DummyBasicMockRule");
assertEquals("Wrong Priority", RulePriority.LOW, dummyBasicMockRule.getPriority());
}
@Test
public void testExcludeWithMinimumPriority() throws RuleSetNotFoundException {
RuleSetFactory rsf = new RuleSetFactory(new ResourceLoader(), RulePriority.HIGH, true, true);
RuleSet ruleset = rsf.createRuleSet("net/sourceforge/pmd/rulesets/ruleset-minimum-priority-exclusion.xml");
// no rules should be loaded
assertEquals("Number of Rules", 0, ruleset.getRules().size());
// now, load with default minimum priority
rsf = new RuleSetFactory();
ruleset = rsf.createRuleSet("net/sourceforge/pmd/rulesets/ruleset-minimum-priority-exclusion.xml");
// only one rule, we have excluded one...
assertEquals("Number of Rules", 1, ruleset.getRules().size());
// rule is excluded
assertNull(ruleset.getRuleByName("DummyBasicMockRule"));
// that's the remaining rule
assertNotNull(ruleset.getRuleByName("SampleXPathRule"));
}
@Test @Test
public void testOverrideMessage() throws RuleSetNotFoundException { public void testOverrideMessage() throws RuleSetNotFoundException {
Rule r = loadFirstRule(REF_OVERRIDE_ORIGINAL_NAME); Rule r = loadFirstRule(REF_OVERRIDE_ORIGINAL_NAME);

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<ruleset name="Test Reference Ruleset" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
Ruleset used by test RuleSetFactoryTest
</description>
<!-- Load in the complete basic ruleset -->
<rule ref="rulesets/dummy/basic.xml">
<!-- but exclude DummyBasicMockRule -->
<exclude name="DummyBasicMockRule"/>
</rule>
</ruleset>

View File

@ -0,0 +1,17 @@
<?xml version="1.0"?>
<ruleset name="Test Reference Ruleset" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<description>
Ruleset used by test RuleSetFactoryTest
</description>
<!-- Load in the complete basic ruleset -->
<rule ref="rulesets/dummy/basic.xml" />
<!-- Override the priority of a specific rule -->
<rule ref="rulesets/dummy/basic.xml/DummyBasicMockRule">
<priority>5</priority> <!-- original priority: 3 -->
</rule>
</ruleset>

View File

@ -32,5 +32,5 @@ Just for test
]]></value> ]]></value>
</property> </property>
</properties> </properties>
</rule>" </rule>
</ruleset> </ruleset>