parent
00f52b388c
commit
f88a2cda5b
@ -0,0 +1,60 @@
|
||||
package org.jeasy.rules.mvel;
|
||||
|
||||
import org.jeasy.rules.api.Facts;
|
||||
import org.jeasy.rules.api.Rule;
|
||||
|
||||
public class MVELActivationRuleGroup extends MVELCompositeRule {
|
||||
|
||||
private Rule selectedRule;
|
||||
|
||||
public MVELActivationRuleGroup() { super(); }
|
||||
|
||||
/**
|
||||
* Set rule name.
|
||||
*
|
||||
* @param name of the rule
|
||||
* @return this rule
|
||||
*/
|
||||
public MVELActivationRuleGroup name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rule description.
|
||||
*
|
||||
* @param description of the rule
|
||||
* @return this rule
|
||||
*/
|
||||
public MVELActivationRuleGroup description(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rule priority.
|
||||
*
|
||||
* @param priority of the rule
|
||||
* @return this rule
|
||||
*/
|
||||
public MVELActivationRuleGroup priority(int priority) {
|
||||
this.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
@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,54 @@
|
||||
package org.jeasy.rules.mvel;
|
||||
|
||||
import org.jeasy.rules.api.Rule;
|
||||
import org.jeasy.rules.core.RuleProxy;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public abstract class MVELCompositeRule extends MVELRule {
|
||||
|
||||
protected Set<Rule> rules;
|
||||
|
||||
private Map<Object, Rule> proxyRules;
|
||||
|
||||
/**
|
||||
* Create a new MVEL composite rule.
|
||||
*/
|
||||
public MVELCompositeRule() {
|
||||
super();
|
||||
rules = new TreeSet<>();
|
||||
proxyRules = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a rule to the composite rule.
|
||||
* @param rule the rule to add
|
||||
*/
|
||||
public void addRule(final Object rule) {
|
||||
Rule proxy = RuleProxy.asRule(rule);
|
||||
rules.add(proxy);
|
||||
proxyRules.put(rule, proxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a rule from the composite rule.
|
||||
* @param rule the rule to remove
|
||||
*/
|
||||
public void removeRule(final Object rule) {
|
||||
Rule proxy = proxyRules.get(rule);
|
||||
if (proxy != null) {
|
||||
rules.remove(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the member rules in this composite.
|
||||
*/
|
||||
public Set<Rule> getRules() {
|
||||
return rules;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package org.jeasy.rules.mvel;
|
||||
|
||||
import org.jeasy.rules.api.Facts;
|
||||
import org.jeasy.rules.api.Rule;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MVELConditionalRuleGroup extends MVELCompositeRule {
|
||||
|
||||
private Set<Rule> successfulEvaluations;
|
||||
private Rule conditionalRule;
|
||||
|
||||
public MVELConditionalRuleGroup() { super(); }
|
||||
|
||||
/**
|
||||
* Set rule name.
|
||||
*
|
||||
* @param name of the rule
|
||||
* @return this rule
|
||||
*/
|
||||
public MVELConditionalRuleGroup name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rule description.
|
||||
*
|
||||
* @param description of the rule
|
||||
* @return this rule
|
||||
*/
|
||||
public MVELConditionalRuleGroup description(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rule priority.
|
||||
*
|
||||
* @param priority of the rule
|
||||
* @return this rule
|
||||
*/
|
||||
public MVELConditionalRuleGroup priority(int priority) {
|
||||
this.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean evaluate(Facts facts) {
|
||||
successfulEvaluations = new HashSet<>();
|
||||
conditionalRule = getRuleWithHighestPriority();
|
||||
if (conditionalRule.evaluate(facts)) {
|
||||
for (Rule rule : rules) {
|
||||
if (rule != conditionalRule && rule.evaluate(facts)) {
|
||||
successfulEvaluations.add(rule);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Facts facts) throws Exception {
|
||||
conditionalRule.execute(facts);
|
||||
for (Rule rule : successfulEvaluations) {
|
||||
rule.execute(facts);
|
||||
}
|
||||
}
|
||||
|
||||
private Rule getRuleWithHighestPriority() {
|
||||
List<Rule> copy = sortRules();
|
||||
// make sure that we only have one rule with the highest priority
|
||||
Rule highest = copy.get(0);
|
||||
if (copy.size() > 1 && copy.get(1).getPriority() == highest.getPriority()) {
|
||||
throw new IllegalArgumentException("Only one rule can have highest priority");
|
||||
}
|
||||
return highest;
|
||||
}
|
||||
|
||||
private List<Rule> sortRules() {
|
||||
List<Rule> copy = new ArrayList<>(rules);
|
||||
Collections.sort(copy, new Comparator<Rule>() {
|
||||
@Override
|
||||
public int compare(Rule o1, Rule o2) {
|
||||
Integer i2 = o2.getPriority();
|
||||
return i2.compareTo(o1.getPriority());
|
||||
}
|
||||
});
|
||||
return copy;
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package org.jeasy.rules.mvel;
|
||||
|
||||
import org.jeasy.rules.api.Facts;
|
||||
import org.jeasy.rules.api.Rule;
|
||||
|
||||
public class MVELUnitRuleGroup extends MVELCompositeRule {
|
||||
|
||||
public MVELUnitRuleGroup() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rule name.
|
||||
*
|
||||
* @param name of the rule
|
||||
* @return this rule
|
||||
*/
|
||||
public MVELUnitRuleGroup name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rule description.
|
||||
*
|
||||
* @param description of the rule
|
||||
* @return this rule
|
||||
*/
|
||||
public MVELUnitRuleGroup description(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rule priority.
|
||||
*
|
||||
* @param priority of the rule
|
||||
* @return this rule
|
||||
*/
|
||||
public MVELUnitRuleGroup priority(int priority) {
|
||||
this.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(Facts facts) {
|
||||
if (!rules.isEmpty()) {
|
||||
for (Rule rule : rules) {
|
||||
if (!rule.evaluate(facts)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Facts facts) throws Exception {
|
||||
for (Rule rule : rules) {
|
||||
rule.execute(facts);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.jeasy.rules.mvel;
|
||||
|
||||
import org.jeasy.rules.api.Facts;
|
||||
|
||||
|
||||
@org.jeasy.rules.annotation.Rule(name = "myRule", description = "my rule description")
|
||||
public class AnnotatedMVELRule extends MVELRule {
|
||||
|
||||
private boolean executed;
|
||||
private boolean evaluated;
|
||||
|
||||
public boolean evaluate(Facts facts) {
|
||||
evaluated = true;
|
||||
return super.evaluate(facts);
|
||||
}
|
||||
|
||||
public void execute(Facts facts) throws Exception {
|
||||
super.execute(facts);
|
||||
executed = true;
|
||||
}
|
||||
|
||||
public boolean isExecuted() { return executed; }
|
||||
|
||||
public boolean isEvaluated() { return evaluated; }
|
||||
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package org.jeasy.rules.mvel;
|
||||
|
||||
import org.jeasy.rules.annotation.Action;
|
||||
import org.jeasy.rules.annotation.Condition;
|
||||
import org.jeasy.rules.annotation.Priority;
|
||||
import org.jeasy.rules.api.Facts;
|
||||
import org.jeasy.rules.api.Rule;
|
||||
import org.jeasy.rules.api.Rules;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class MVELActivationRuleGroupTest {
|
||||
private Facts facts = new Facts();
|
||||
private MVELActivationRuleGroup activationRuleGroup;
|
||||
private MVELRule subrule1 = new AnnotatedMVELRule()
|
||||
.name("subrule1")
|
||||
.priority(1)
|
||||
.when("person.age > 18")
|
||||
.then("person.setAdult(true);");
|
||||
private MVELRule subrule2 = new AnnotatedMVELRule()
|
||||
.name("subrule2")
|
||||
.priority(2)
|
||||
.when("person.age > 13")
|
||||
.then("person.setTeenager(true);");
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
activationRuleGroup = new MVELActivationRuleGroup()
|
||||
.name("activation rule group")
|
||||
.description("description")
|
||||
.priority(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTheRuleIsTriggered_conditionEvaluatesTrue() throws Exception {
|
||||
activationRuleGroup.addRule(subrule1);
|
||||
activationRuleGroup.addRule(subrule2);
|
||||
|
||||
// given
|
||||
facts.put("person", new Person("foo", 20));
|
||||
|
||||
// when
|
||||
boolean evaluationResult = activationRuleGroup.evaluate(facts);
|
||||
|
||||
// then
|
||||
assertThat(evaluationResult).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule1).isEvaluated()).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule2).isEvaluated()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTheRuleIsTriggered_conditionEvaluatesFalse() throws Exception {
|
||||
activationRuleGroup.addRule(subrule1);
|
||||
activationRuleGroup.addRule(subrule2);
|
||||
|
||||
// given
|
||||
facts.put("person", new Person("foo", 12));
|
||||
|
||||
// when
|
||||
boolean evaluationResult = activationRuleGroup.evaluate(facts);
|
||||
|
||||
// then
|
||||
assertThat(evaluationResult).isFalse();
|
||||
assertThat(((AnnotatedMVELRule) subrule1).isEvaluated()).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule2).isEvaluated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTheConditionIsTrue_thenActionsShouldBeExecuted() throws Exception {
|
||||
activationRuleGroup.addRule(subrule1);
|
||||
activationRuleGroup.addRule(subrule2);
|
||||
|
||||
// given
|
||||
Person foo = new Person("foo", 20);
|
||||
facts.put("person", foo);
|
||||
|
||||
// when
|
||||
activationRuleGroup.evaluate(facts);
|
||||
activationRuleGroup.execute(facts);
|
||||
|
||||
// then
|
||||
assertThat(foo.isAdult()).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule1).isExecuted()).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule2).isExecuted()).isFalse();
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package org.jeasy.rules.mvel;
|
||||
|
||||
import org.jeasy.rules.api.Facts;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class MVELConditionalRuleGroupTest {
|
||||
private Facts facts = new Facts();
|
||||
private MVELConditionalRuleGroup conditionalRuleGroup;
|
||||
private MVELRule subrule1 = new AnnotatedMVELRule()
|
||||
.name("subrule1")
|
||||
.priority(1)
|
||||
.when("person.age > 18")
|
||||
.then("person.orderDrink();");
|
||||
private MVELRule subrule2 = new AnnotatedMVELRule()
|
||||
.name("subrule2")
|
||||
.priority(2)
|
||||
.when("person.age > 18")
|
||||
.then("person.setAdult(true);");
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
conditionalRuleGroup = new MVELConditionalRuleGroup()
|
||||
.name("conditional rule group")
|
||||
.description("description")
|
||||
.priority(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTheRuleIsTriggered_conditionEvaluatesTrue() throws Exception {
|
||||
conditionalRuleGroup.addRule(subrule1);
|
||||
conditionalRuleGroup.addRule(subrule2);
|
||||
|
||||
// given
|
||||
facts.put("person", new Person("foo", 20));
|
||||
|
||||
// when
|
||||
boolean evaluationResult = conditionalRuleGroup.evaluate(facts);
|
||||
|
||||
// then
|
||||
assertThat(evaluationResult).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule1).isEvaluated()).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule2).isEvaluated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTheRuleIsTriggered_conditionEvaluatesFalse() throws Exception {
|
||||
conditionalRuleGroup.addRule(subrule1);
|
||||
conditionalRuleGroup.addRule(subrule2);
|
||||
|
||||
// given
|
||||
facts.put("person", new Person("foo", 16));
|
||||
|
||||
// when
|
||||
boolean evaluationResult = conditionalRuleGroup.evaluate(facts);
|
||||
|
||||
// then
|
||||
assertThat(evaluationResult).isFalse();
|
||||
assertThat(((AnnotatedMVELRule) subrule1).isEvaluated()).isFalse();
|
||||
assertThat(((AnnotatedMVELRule) subrule2).isEvaluated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTheConditionIsTrue_thenActionsShouldBeExecuted() throws Exception {
|
||||
conditionalRuleGroup.addRule(subrule1);
|
||||
conditionalRuleGroup.addRule(subrule2);
|
||||
|
||||
// given
|
||||
Person foo = new Person("foo", 20);
|
||||
facts.put("person", foo);
|
||||
|
||||
// when
|
||||
conditionalRuleGroup.evaluate(facts);
|
||||
conditionalRuleGroup.execute(facts);
|
||||
|
||||
// then
|
||||
assertThat(foo.isAdult()).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule1).isExecuted()).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule2).isExecuted()).isTrue();
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package org.jeasy.rules.mvel;
|
||||
|
||||
import org.jeasy.rules.api.Facts;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class MVELUnitRuleGroupTest {
|
||||
private Facts facts = new Facts();
|
||||
private MVELUnitRuleGroup unitRuleGroup;
|
||||
private MVELRule subrule1 = new AnnotatedMVELRule()
|
||||
.name("subrule1")
|
||||
.priority(1)
|
||||
.when("person.age > 18")
|
||||
.then("person.setAdult(true);");
|
||||
private MVELRule subrule2 = new AnnotatedMVELRule()
|
||||
.name("subrule2")
|
||||
.priority(1)
|
||||
.when("person.age >= 21")
|
||||
.then("person.setCanDrinkInUS(true);");
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
unitRuleGroup = new MVELUnitRuleGroup()
|
||||
.name("unit rule group")
|
||||
.description("description")
|
||||
.priority(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTheRuleIsTriggered_conditionEvaluatesTrue() throws Exception {
|
||||
unitRuleGroup.addRule(subrule1);
|
||||
unitRuleGroup.addRule(subrule2);
|
||||
|
||||
// given
|
||||
facts.put("person", new Person("foo", 21));
|
||||
|
||||
// when
|
||||
boolean evaluationResult = unitRuleGroup.evaluate(facts);
|
||||
|
||||
// then
|
||||
assertThat(evaluationResult).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule1).isEvaluated()).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule2).isEvaluated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTheRuleIsTriggered_conditionEvaluatesFalse() throws Exception {
|
||||
MVELRule subrule3 = new AnnotatedMVELRule()
|
||||
.name("subrule3")
|
||||
.priority(1)
|
||||
.when("person.age < 18")
|
||||
.then("System.out.println(\"Not an adult\");");
|
||||
unitRuleGroup.addRule(subrule1);
|
||||
unitRuleGroup.addRule(subrule3);
|
||||
|
||||
// given
|
||||
facts.put("person", new Person("foo", 20));
|
||||
|
||||
// when
|
||||
boolean evaluationResult = unitRuleGroup.evaluate(facts);
|
||||
|
||||
// then
|
||||
assertThat(evaluationResult).isFalse();
|
||||
assertThat(((AnnotatedMVELRule) subrule1).isEvaluated()).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule3).isEvaluated()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTheConditionIsTrue_thenActionsShouldBeExecuted() throws Exception {
|
||||
unitRuleGroup.addRule(subrule1);
|
||||
unitRuleGroup.addRule(subrule2);
|
||||
|
||||
// given
|
||||
Person foo = new Person("foo", 20);
|
||||
facts.put("person", foo);
|
||||
|
||||
// when
|
||||
unitRuleGroup.execute(facts);
|
||||
|
||||
// then
|
||||
assertThat(foo.isAdult()).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule1).isExecuted()).isTrue();
|
||||
assertThat(((AnnotatedMVELRule) subrule2).isExecuted()).isTrue();
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
name: Movie id rule
|
||||
compositeType: UnitRuleGroup
|
||||
priority: 1
|
||||
subrules:
|
||||
- name: Time is evening
|
||||
description: If it's later than 7pm
|
||||
priority: 1
|
||||
condition: "day.hour > 19"
|
||||
actions:
|
||||
- "person.shouldProvideId(true);"
|
||||
- name: Movie is rated R
|
||||
description: If the movie is rated R
|
||||
priority: 1
|
||||
condition: "movie.rating == R"
|
||||
actions:
|
||||
- "person.shouldProvideId(true);"
|
||||
---
|
||||
name: weather rule
|
||||
description: when it rains, then take an umbrella
|
||||
priority: 1
|
||||
condition: "rain == True"
|
||||
actions:
|
||||
- "System.out.println(\"It rains, take an umbrella!\");"
|
Loading…
Reference in New Issue