diff --git a/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRule.java b/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRule.java index eb88b1f..12981ed 100644 --- a/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRule.java +++ b/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRule.java @@ -28,6 +28,7 @@ import org.jeasy.rules.api.Condition; import org.jeasy.rules.api.Facts; import org.jeasy.rules.api.Rule; import org.jeasy.rules.core.BasicRule; +import org.mvel2.ParserContext; import java.util.ArrayList; import java.util.List; @@ -88,7 +89,17 @@ public class MVELRule extends BasicRule { * @return this rule */ 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; } @@ -98,7 +109,17 @@ public class MVELRule extends BasicRule { * @return this rule */ 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; } diff --git a/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleDefinition.java b/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleDefinition.java index d41b215..a98ca0c 100644 --- a/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleDefinition.java +++ b/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleDefinition.java @@ -24,14 +24,8 @@ package org.jeasy.rules.mvel; 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.Arrays; import java.util.List; class MVELRuleDefinition { @@ -40,12 +34,9 @@ class MVELRuleDefinition { private String description = Rule.DEFAULT_DESCRIPTION; private int priority = Rule.DEFAULT_PRIORITY; private String condition; - private List actions; - private Rules composingRules; + private List actions = new ArrayList<>(); + private List composingRules = new ArrayList<>(); private String compositeRuleType; - private List allowedCompositeRuleTypes = new ArrayList<>( - Arrays.asList(UnitRuleGroup.class.getSimpleName(), ConditionalRuleGroup.class.getSimpleName(), ActivationRuleGroup.class.getSimpleName()) - ); public String getName() { return name; @@ -88,11 +79,7 @@ class MVELRuleDefinition { } void setComposingRules(List composingRuleDefinitions) { - composingRules = new Rules(); - for (MVELRuleDefinition ruleDefinition : composingRuleDefinitions) { - Rule rule = ruleDefinition.create(); - composingRules.register(rule); - } + this.composingRules = composingRuleDefinitions; } void setCompositeRuleType(String compositeRuleType) { @@ -103,56 +90,11 @@ class MVELRuleDefinition { return compositeRuleType; } - Rules getComposingRules() { + List getComposingRules() { return composingRules; } - Rule create() { - if (isCompositeRule()) { - 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; + boolean isCompositeRule() { + return !composingRules.isEmpty(); } } \ No newline at end of file diff --git a/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleDefinitionReader.java b/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleDefinitionReader.java index 1045ed5..09cb111 100644 --- a/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleDefinitionReader.java +++ b/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleDefinitionReader.java @@ -86,8 +86,8 @@ class MVELRuleDefinitionReader { } else if (composingRules != null) { List composingRuleDefinitions = new ArrayList<>(); for (Object rule : composingRules){ - Map composingRulesMap = (Map) rule; - composingRuleDefinitions.add(createRuleDefinitionFrom(composingRulesMap)); + Map composingRuleMap = (Map) rule; + composingRuleDefinitions.add(createRuleDefinitionFrom(composingRuleMap)); } ruleDefinition.setComposingRules(composingRuleDefinitions); ruleDefinition.setCompositeRuleType(compositeRuleType); diff --git a/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleFactory.java b/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleFactory.java index 3c22261..75cd4f3 100644 --- a/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleFactory.java +++ b/easy-rules-mvel/src/main/java/org/jeasy/rules/mvel/MVELRuleFactory.java @@ -25,8 +25,14 @@ package org.jeasy.rules.mvel; 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 org.mvel2.ParserContext; import java.io.Reader; +import java.util.Arrays; import java.util.List; /** @@ -36,7 +42,13 @@ import java.util.List; */ public class MVELRuleFactory { - private static MVELRuleDefinitionReader reader = new MVELRuleDefinitionReader(); + private static final MVELRuleDefinitionReader READER = new MVELRuleDefinitionReader(); + + private static final List ALLOWED_COMPOSITE_RULE_TYPES = Arrays.asList( + UnitRuleGroup.class.getSimpleName(), + ConditionalRuleGroup.class.getSimpleName(), + ActivationRuleGroup.class.getSimpleName() + ); /** * Create a new {@link MVELRule} from a Reader. @@ -45,8 +57,19 @@ public class MVELRuleFactory { * @return a new rule */ public static Rule createRuleFrom(Reader ruleDescriptor) { - MVELRuleDefinition ruleDefinition = reader.read(ruleDescriptor); - return ruleDefinition.create(); + return createRuleFrom(ruleDescriptor, new ParserContext()); + } + + /** + * 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 */ 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(); - List ruleDefinition = reader.readAll(rulesDescriptor); + List ruleDefinition = READER.readAll(rulesDescriptor); for (MVELRuleDefinition mvelRuleDefinition : ruleDefinition) { - rules.register(mvelRuleDefinition.create()); + rules.register(createRule(mvelRuleDefinition, parserContext)); } 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; + } } diff --git a/easy-rules-mvel/src/test/java/org/jeasy/rules/mvel/MVELRuleDefinitionReaderTest.java b/easy-rules-mvel/src/test/java/org/jeasy/rules/mvel/MVELRuleDefinitionReaderTest.java index a05f7e0..ac669fd 100644 --- a/easy-rules-mvel/src/test/java/org/jeasy/rules/mvel/MVELRuleDefinitionReaderTest.java +++ b/easy-rules-mvel/src/test/java/org/jeasy/rules/mvel/MVELRuleDefinitionReaderTest.java @@ -172,28 +172,28 @@ public class MVELRuleDefinitionReaderTest { assertThat(ruleDefinition).isNotNull(); assertThat(ruleDefinition.getName()).isEqualTo("Movie id rule"); assertThat(ruleDefinition.getDescription()).isEqualTo("description"); + assertThat(ruleDefinition.getPriority()).isEqualTo(1); assertThat(ruleDefinition.getCompositeRuleType()).isEqualTo("UnitRuleGroup"); assertThat(ruleDefinition.getComposingRules()).isNotEmpty(); - Rules subrules = ruleDefinition.getComposingRules(); + List subrules = ruleDefinition.getComposingRules(); assertThat(subrules).hasSize(2); - Iterator 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.getDescription()).isEqualTo("If it's later than 7pm"); 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); assertThat(ruleDefinition).isNotNull(); assertThat(ruleDefinition.getName()).isEqualTo("weather rule"); 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.getActions()).isEqualTo(Collections.singletonList("System.out.println(\"It rains, take an umbrella!\");")); }