Add support to load rules with a ParserContext in MVELRuleFactory

Resolves #197
pull/200/head
Mahmoud Ben Hassine 6 years ago
parent c83ff59da8
commit 3f6e87b202

@ -28,6 +28,7 @@ import org.jeasy.rules.api.Condition;
import org.jeasy.rules.api.Facts; import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rule; import org.jeasy.rules.api.Rule;
import org.jeasy.rules.core.BasicRule; import org.jeasy.rules.core.BasicRule;
import org.mvel2.ParserContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -88,7 +89,17 @@ public class MVELRule extends BasicRule {
* @return this rule * @return this rule
*/ */
public MVELRule when(String condition) { public MVELRule when(String condition) {
this.condition = new MVELCondition(condition); return this.when(condition, new ParserContext());
}
/**
* Specify the rule's condition as MVEL expression.
* @param condition of the rule
* @param parserContext the MVEL parser context
* @return this rule
*/
public MVELRule when(String condition, ParserContext parserContext) {
this.condition = new MVELCondition(condition, parserContext);
return this; return this;
} }
@ -98,7 +109,17 @@ public class MVELRule extends BasicRule {
* @return this rule * @return this rule
*/ */
public MVELRule then(String action) { public MVELRule then(String action) {
this.actions.add(new MVELAction(action)); return this.then(action, new ParserContext());
}
/**
* Add an action specified as an MVEL expression to the rule.
* @param action to add to the rule
* @param parserContext the MVEL parser context
* @return this rule
*/
public MVELRule then(String action, ParserContext parserContext) {
this.actions.add(new MVELAction(action, parserContext));
return this; return this;
} }

@ -24,14 +24,8 @@
package org.jeasy.rules.mvel; package org.jeasy.rules.mvel;
import org.jeasy.rules.api.Rule; import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.support.ActivationRuleGroup;
import org.jeasy.rules.support.CompositeRule;
import org.jeasy.rules.support.ConditionalRuleGroup;
import org.jeasy.rules.support.UnitRuleGroup;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
class MVELRuleDefinition { class MVELRuleDefinition {
@ -40,12 +34,9 @@ class MVELRuleDefinition {
private String description = Rule.DEFAULT_DESCRIPTION; private String description = Rule.DEFAULT_DESCRIPTION;
private int priority = Rule.DEFAULT_PRIORITY; private int priority = Rule.DEFAULT_PRIORITY;
private String condition; private String condition;
private List<String> actions; private List<String> actions = new ArrayList<>();
private Rules composingRules; private List<MVELRuleDefinition> composingRules = new ArrayList<>();
private String compositeRuleType; private String compositeRuleType;
private List<String> allowedCompositeRuleTypes = new ArrayList<>(
Arrays.asList(UnitRuleGroup.class.getSimpleName(), ConditionalRuleGroup.class.getSimpleName(), ActivationRuleGroup.class.getSimpleName())
);
public String getName() { public String getName() {
return name; return name;
@ -88,11 +79,7 @@ class MVELRuleDefinition {
} }
void setComposingRules(List<MVELRuleDefinition> composingRuleDefinitions) { void setComposingRules(List<MVELRuleDefinition> composingRuleDefinitions) {
composingRules = new Rules(); this.composingRules = composingRuleDefinitions;
for (MVELRuleDefinition ruleDefinition : composingRuleDefinitions) {
Rule rule = ruleDefinition.create();
composingRules.register(rule);
}
} }
void setCompositeRuleType(String compositeRuleType) { void setCompositeRuleType(String compositeRuleType) {
@ -103,56 +90,11 @@ class MVELRuleDefinition {
return compositeRuleType; return compositeRuleType;
} }
Rules getComposingRules() { List<MVELRuleDefinition> getComposingRules() {
return composingRules; return composingRules;
} }
Rule create() { boolean isCompositeRule() {
if (isCompositeRule()) { return !composingRules.isEmpty();
return createCompositeRule();
} else {
return createSimpleRule();
}
}
private Rule createSimpleRule() {
MVELRule mvelRule = new MVELRule()
.name(name)
.description(description)
.priority(priority)
.when(condition);
for (String action : actions) {
mvelRule.then(action);
}
return mvelRule;
}
private Rule createCompositeRule() {
CompositeRule compositeRule;
switch (compositeRuleType) {
case "UnitRuleGroup":
compositeRule = new UnitRuleGroup(name);
break;
case "ActivationRuleGroup":
compositeRule = new ActivationRuleGroup(name);
break;
case "ConditionalRuleGroup":
compositeRule = new ConditionalRuleGroup(name);
break;
default:
throw new IllegalArgumentException("Invalid composite rule type, must be one of " + allowedCompositeRuleTypes);
}
compositeRule.setDescription(description);
compositeRule.setPriority(priority);
for (Rule rule : composingRules) {
compositeRule.addRule(rule);
}
return compositeRule;
}
private boolean isCompositeRule() {
return composingRules != null;
} }
} }

@ -86,8 +86,8 @@ class MVELRuleDefinitionReader {
} else if (composingRules != null) { } else if (composingRules != null) {
List<MVELRuleDefinition> composingRuleDefinitions = new ArrayList<>(); List<MVELRuleDefinition> composingRuleDefinitions = new ArrayList<>();
for (Object rule : composingRules){ for (Object rule : composingRules){
Map<String, Object> composingRulesMap = (Map<String, Object>) rule; Map<String, Object> composingRuleMap = (Map<String, Object>) rule;
composingRuleDefinitions.add(createRuleDefinitionFrom(composingRulesMap)); composingRuleDefinitions.add(createRuleDefinitionFrom(composingRuleMap));
} }
ruleDefinition.setComposingRules(composingRuleDefinitions); ruleDefinition.setComposingRules(composingRuleDefinitions);
ruleDefinition.setCompositeRuleType(compositeRuleType); ruleDefinition.setCompositeRuleType(compositeRuleType);

@ -25,8 +25,14 @@ package org.jeasy.rules.mvel;
import org.jeasy.rules.api.Rule; import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.Rules; import org.jeasy.rules.api.Rules;
import org.jeasy.rules.support.ActivationRuleGroup;
import org.jeasy.rules.support.CompositeRule;
import org.jeasy.rules.support.ConditionalRuleGroup;
import org.jeasy.rules.support.UnitRuleGroup;
import org.mvel2.ParserContext;
import java.io.Reader; import java.io.Reader;
import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
@ -36,7 +42,13 @@ import java.util.List;
*/ */
public class MVELRuleFactory { public class MVELRuleFactory {
private static MVELRuleDefinitionReader reader = new MVELRuleDefinitionReader(); private static final MVELRuleDefinitionReader READER = new MVELRuleDefinitionReader();
private static final List<String> ALLOWED_COMPOSITE_RULE_TYPES = Arrays.asList(
UnitRuleGroup.class.getSimpleName(),
ConditionalRuleGroup.class.getSimpleName(),
ActivationRuleGroup.class.getSimpleName()
);
/** /**
* Create a new {@link MVELRule} from a Reader. * Create a new {@link MVELRule} from a Reader.
@ -45,8 +57,19 @@ public class MVELRuleFactory {
* @return a new rule * @return a new rule
*/ */
public static Rule createRuleFrom(Reader ruleDescriptor) { public static Rule createRuleFrom(Reader ruleDescriptor) {
MVELRuleDefinition ruleDefinition = reader.read(ruleDescriptor); return createRuleFrom(ruleDescriptor, new ParserContext());
return ruleDefinition.create(); }
/**
* Create a new {@link MVELRule} from a Reader.
*
* @param ruleDescriptor as a Reader
* @param parserContext the MVEL parser context
* @return a new rule
*/
public static Rule createRuleFrom(Reader ruleDescriptor, ParserContext parserContext) {
MVELRuleDefinition ruleDefinition = READER.read(ruleDescriptor);
return createRule(ruleDefinition, parserContext);
} }
/** /**
@ -56,11 +79,67 @@ public class MVELRuleFactory {
* @return a set of rules * @return a set of rules
*/ */
public static Rules createRulesFrom(Reader rulesDescriptor) { public static Rules createRulesFrom(Reader rulesDescriptor) {
return createRulesFrom(rulesDescriptor, new ParserContext());
}
/**
* Create a set of {@link MVELRule} from a Reader.
*
* @param rulesDescriptor as a Reader
* @return a set of rules
*/
public static Rules createRulesFrom(Reader rulesDescriptor, ParserContext parserContext) {
Rules rules = new Rules(); Rules rules = new Rules();
List<MVELRuleDefinition> ruleDefinition = reader.readAll(rulesDescriptor); List<MVELRuleDefinition> ruleDefinition = READER.readAll(rulesDescriptor);
for (MVELRuleDefinition mvelRuleDefinition : ruleDefinition) { for (MVELRuleDefinition mvelRuleDefinition : ruleDefinition) {
rules.register(mvelRuleDefinition.create()); rules.register(createRule(mvelRuleDefinition, parserContext));
} }
return rules; return rules;
} }
private static Rule createRule(MVELRuleDefinition ruleDefinition, ParserContext context) {
if (ruleDefinition.isCompositeRule()) {
return createCompositeRule(ruleDefinition, context);
} else {
return createSimpleRule(ruleDefinition, context);
}
}
private static Rule createSimpleRule(MVELRuleDefinition ruleDefinition, ParserContext parserContext) {
MVELRule mvelRule = new MVELRule()
.name(ruleDefinition.getName())
.description(ruleDefinition.getDescription())
.priority(ruleDefinition.getPriority())
.when(ruleDefinition.getCondition(), parserContext);
for (String action : ruleDefinition.getActions()) {
mvelRule.then(action, parserContext);
}
return mvelRule;
}
private static Rule createCompositeRule(MVELRuleDefinition ruleDefinition, ParserContext parserContext) {
CompositeRule compositeRule;
String name = ruleDefinition.getName();
switch (ruleDefinition.getCompositeRuleType()) {
case "UnitRuleGroup":
compositeRule = new UnitRuleGroup(name);
break;
case "ActivationRuleGroup":
compositeRule = new ActivationRuleGroup(name);
break;
case "ConditionalRuleGroup":
compositeRule = new ConditionalRuleGroup(name);
break;
default:
throw new IllegalArgumentException("Invalid composite rule type, must be one of " + ALLOWED_COMPOSITE_RULE_TYPES);
}
compositeRule.setDescription(ruleDefinition.getDescription());
compositeRule.setPriority(ruleDefinition.getPriority());
for (MVELRuleDefinition composingRuleDefinition : ruleDefinition.getComposingRules()) {
compositeRule.addRule(createRule(composingRuleDefinition, parserContext));
}
return compositeRule;
}
} }

@ -172,28 +172,28 @@ public class MVELRuleDefinitionReaderTest {
assertThat(ruleDefinition).isNotNull(); assertThat(ruleDefinition).isNotNull();
assertThat(ruleDefinition.getName()).isEqualTo("Movie id rule"); assertThat(ruleDefinition.getName()).isEqualTo("Movie id rule");
assertThat(ruleDefinition.getDescription()).isEqualTo("description"); assertThat(ruleDefinition.getDescription()).isEqualTo("description");
assertThat(ruleDefinition.getPriority()).isEqualTo(1);
assertThat(ruleDefinition.getCompositeRuleType()).isEqualTo("UnitRuleGroup"); assertThat(ruleDefinition.getCompositeRuleType()).isEqualTo("UnitRuleGroup");
assertThat(ruleDefinition.getComposingRules()).isNotEmpty(); assertThat(ruleDefinition.getComposingRules()).isNotEmpty();
Rules subrules = ruleDefinition.getComposingRules(); List<MVELRuleDefinition> subrules = ruleDefinition.getComposingRules();
assertThat(subrules).hasSize(2); assertThat(subrules).hasSize(2);
Iterator<Rule> iterator = subrules.iterator();
Rule subrule = iterator.next();
assertThat(subrule.getName()).isEqualTo("Movie is rated R");
assertThat(subrule.getDescription()).isEqualTo("If the movie is rated R");
assertThat(subrule.getPriority()).isEqualTo(1);
subrule = iterator.next(); MVELRuleDefinition subrule = subrules.get(0);
assertThat(subrule.getName()).isEqualTo("Time is evening"); assertThat(subrule.getName()).isEqualTo("Time is evening");
assertThat(subrule.getDescription()).isEqualTo("If it's later than 7pm"); assertThat(subrule.getDescription()).isEqualTo("If it's later than 7pm");
assertThat(subrule.getPriority()).isEqualTo(1); assertThat(subrule.getPriority()).isEqualTo(1);
subrule = subrules.get(1);
assertThat(subrule.getName()).isEqualTo("Movie is rated R");
assertThat(subrule.getDescription()).isEqualTo("If the movie is rated R");
assertThat(subrule.getPriority()).isEqualTo(1);
ruleDefinition = ruleDefinitions.get(1); ruleDefinition = ruleDefinitions.get(1);
assertThat(ruleDefinition).isNotNull(); assertThat(ruleDefinition).isNotNull();
assertThat(ruleDefinition.getName()).isEqualTo("weather rule"); assertThat(ruleDefinition.getName()).isEqualTo("weather rule");
assertThat(ruleDefinition.getDescription()).isEqualTo("when it rains, then take an umbrella"); assertThat(ruleDefinition.getDescription()).isEqualTo("when it rains, then take an umbrella");
assertThat(ruleDefinition.getComposingRules()).isNull(); assertThat(ruleDefinition.getComposingRules()).isEmpty();
assertThat(ruleDefinition.getCondition()).isEqualTo("rain == True"); assertThat(ruleDefinition.getCondition()).isEqualTo("rain == True");
assertThat(ruleDefinition.getActions()).isEqualTo(Collections.singletonList("System.out.println(\"It rains, take an umbrella!\");")); assertThat(ruleDefinition.getActions()).isEqualTo(Collections.singletonList("System.out.println(\"It rains, take an umbrella!\");"));
} }

Loading…
Cancel
Save