issue #122 : add ActivationRuleGroup implementation

pull/147/head
Mahmoud Ben Hassine 7 years ago
parent ca4b78de8b
commit 583359a229

@ -0,0 +1,96 @@
/**
* The MIT License
*
* Copyright (c) 2017, Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jeasy.rules.support;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rule;
import java.util.TreeSet;
/**
* An activation rule group is a composite rule that fires the first applicable rule and ignores other rules in
* the group (XOR logic). Rules are first sorted by their natural order (priority by default) within the group.
*
* @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com)
*/
public class ActivationRuleGroup extends CompositeRule {
private Rule selectedRule;
/**
* Create an activation rule group.
*/
public ActivationRuleGroup() {
rules = new TreeSet<>(rules);
}
/**
* Create an activation rule group.
*
* @param name of the activation rule group
*/
public ActivationRuleGroup(String name) {
super(name);
rules = new TreeSet<>(rules);
}
/**
* Create a conditional rule group.
*
* @param name of the activation rule group
* @param description of the activation rule group
*/
public ActivationRuleGroup(String name, String description) {
super(name, description);
rules = new TreeSet<>(rules);
}
/**
* Create an activation rule group.
*
* @param name of the activation rule group
* @param description of the activation rule group
* @param priority of the activation rule group
*/
public ActivationRuleGroup(String name, String description, int priority) {
super(name, description, priority);
rules = new TreeSet<>(rules);
}
@Override
public boolean evaluate(Facts facts) {
for (Rule rule : rules) {
if (rule.evaluate(facts)) {
selectedRule = rule;
return true;
}
}
return false;
}
@Override
public void execute(Facts facts) throws Exception {
selectedRule.execute(facts);
}
}

@ -0,0 +1,123 @@
/**
* The MIT License
*
* Copyright (c) 2017, Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jeasy.rules.support;
import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(MockitoJUnitRunner.class)
public class ActivationRuleGroupTest {
private Facts facts = new Facts();
private Rules rules = new Rules();
private DefaultRulesEngine rulesEngine = new DefaultRulesEngine();
@Test
public void onlySelectedRuleShouldBeExecuted_whenComposingRulesHaveDifferentPriorities() {
// given
Rule1 rule1 = new Rule1();
Rule2 rule2 = new Rule2();
ActivationRuleGroup activationRuleGroup = new ActivationRuleGroup("my activation rule", "rule1 xor rule2");
activationRuleGroup.addRule(rule1);
activationRuleGroup.addRule(rule2);
rules.register(activationRuleGroup);
// when
rulesEngine.fire(rules, facts);
// then
assertThat(rule1.isExecuted()).isTrue();
assertThat(rule2.isExecuted()).isFalse();
}
@Test
public void onlySelectedRuleShouldBeExecuted_whenComposingRulesHaveSamePriority() {
// given
Rule2 rule2 = new Rule2();
Rule3 rule3 = new Rule3();
ActivationRuleGroup activationRuleGroup = new ActivationRuleGroup("my activation rule", "rule2 xor rule3");
activationRuleGroup.addRule(rule2);
activationRuleGroup.addRule(rule3);
rules.register(activationRuleGroup);
// when
rulesEngine.fire(rules, facts);
// then
// we don't know upfront which rule will be selected, but only one of them should be executed
if (rule2.isExecuted()) {
assertThat(rule3.isExecuted()).isFalse();
} else {
assertThat(rule3.isExecuted()).isTrue();
}
}
@org.jeasy.rules.annotation.Rule(priority = 1)
public class Rule1 {
private boolean executed;
@Condition
public boolean when() { return true; }
@Action
public void then() { executed = true; }
public boolean isExecuted() { return executed; }
}
@org.jeasy.rules.annotation.Rule(priority = 2)
public class Rule2 {
private boolean executed;
@Condition
public boolean when() { return true; }
@Action
public void then() { executed = true; }
public boolean isExecuted() { return executed; }
}
@org.jeasy.rules.annotation.Rule(priority = 2)
public class Rule3 {
private boolean executed;
@Condition
public boolean when() { return true; }
@Action
public void then() { executed = true; }
public boolean isExecuted() { return executed; }
}
}
Loading…
Cancel
Save