Add support to read rules from json objects

Resolves #202
pull/210/head
Mahmoud Ben Hassine 6 years ago
parent 10905f7f22
commit 84e80f8b33

@ -15,7 +15,7 @@
<properties>
<mvel2.version>2.4.3.Final</mvel2.version>
<system-rules.version>1.19.0</system-rules.version>
<jackson-dataformat-yaml.version>2.9.8</jackson-dataformat-yaml.version>
<jackson.version>2.9.8</jackson.version>
</properties>
<scm>
@ -63,7 +63,12 @@
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>${jackson-dataformat-yaml.version}</version>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>

@ -0,0 +1,120 @@
/**
* The MIT License
*
* Copyright (c) 2019, 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.mvel;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.jeasy.rules.api.Rule;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Rule definition reader based on <a href="https://github.com/FasterXML/jackson">Jackson</a>.
*
* This reader expects an array of rule definitions as input even for a single rule. For example:
*
* <pre>
* [{rule1}, {rule2}]
* </pre>
*
* @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com)
*/
@SuppressWarnings("unchecked")
public class MVELJsonRuleDefinitionReader implements MVELRuleDefinitionReader {
private ObjectMapper objectMapper;
/**
* Create a new {@link MVELJsonRuleDefinitionReader}.
*/
public MVELJsonRuleDefinitionReader() {
objectMapper = new ObjectMapper();
}
/**
* Create a new {@link MVELJsonRuleDefinitionReader}.
*
* @param objectMapper to use to read rule definitions
*/
public MVELJsonRuleDefinitionReader(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
public List<MVELRuleDefinition> read(Reader reader) throws Exception {
List<MVELRuleDefinition> ruleDefinitions = new ArrayList<>();
Object[] rules = objectMapper.readValue(reader, Object[].class );
for (Object rule : rules) {
Map<String, Object> map = (Map<String, Object>) rule;
ruleDefinitions.add(createRuleDefinitionFrom(map));
}
return ruleDefinitions;
}
private MVELRuleDefinition createRuleDefinitionFrom(Map<String, Object> map) {
MVELRuleDefinition ruleDefinition = new MVELRuleDefinition();
String name = (String) map.get("name");
ruleDefinition.setName(name != null ? name : Rule.DEFAULT_NAME);
String description = (String) map.get("description");
ruleDefinition.setDescription(description != null ? description : Rule.DEFAULT_DESCRIPTION);
Integer priority = (Integer) map.get("priority");
ruleDefinition.setPriority(priority != null ? priority : Rule.DEFAULT_PRIORITY);
String compositeRuleType = (String) map.get("compositeRuleType");
String condition = (String) map.get("condition");
if (condition == null && compositeRuleType == null) {
throw new IllegalArgumentException("The rule condition must be specified");
}
ruleDefinition.setCondition(condition);
List<String> actions = (List<String>) map.get("actions");
if ((actions == null || actions.isEmpty()) && compositeRuleType == null) {
throw new IllegalArgumentException("The rule action(s) must be specified");
}
ruleDefinition.setActions(actions);
List<Object> composingRules = (List<Object>) map.get("composingRules");
if (composingRules != null && compositeRuleType == null) {
throw new IllegalArgumentException("Non-composite rules cannot have composing rules");
} else if ((composingRules == null || composingRules.isEmpty()) && compositeRuleType != null) {
throw new IllegalArgumentException("Composite rules must have composing rules specified");
} else if (composingRules != null) {
List<MVELRuleDefinition> composingRuleDefinitions = new ArrayList<>();
for (Object rule : composingRules){
Map<String, Object> composingRuleMap = (Map<String, Object>) rule;
composingRuleDefinitions.add(createRuleDefinitionFrom(composingRuleMap));
}
ruleDefinition.setComposingRules(composingRuleDefinitions);
ruleDefinition.setCompositeRuleType(compositeRuleType);
}
return ruleDefinition;
}
}

@ -28,7 +28,15 @@ import org.jeasy.rules.api.Rule;
import java.util.ArrayList;
import java.util.List;
class MVELRuleDefinition {
/**
* Rule definition as defined in a rule description.
* This class encapsulates static definition of an {@link MVELRule}.
*
* This definition is produced by a {@link MVELRuleDefinitionReader}.
*
* @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com)
*/
public class MVELRuleDefinition {
private String name = Rule.DEFAULT_NAME;
private String description = Rule.DEFAULT_DESCRIPTION;

@ -23,76 +23,28 @@
*/
package org.jeasy.rules.mvel;
import org.jeasy.rules.api.Rule;
import org.yaml.snakeyaml.Yaml;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@SuppressWarnings("unchecked")
class MVELRuleDefinitionReader {
private Yaml yaml = new Yaml();
MVELRuleDefinition read(Reader reader) {
Object object = yaml.load(reader);
Map<String, Object> map = (Map<String, Object>) object;
return createRuleDefinitionFrom(map);
}
List<MVELRuleDefinition> readAll(Reader reader) {
List<MVELRuleDefinition> ruleDefinitions = new ArrayList<>();
Iterable<Object> rules = yaml.loadAll(reader);
for (Object rule : rules) {
Map<String, Object> map = (Map<String, Object>) rule;
ruleDefinitions.add(createRuleDefinitionFrom(map));
}
return ruleDefinitions;
}
private static MVELRuleDefinition createRuleDefinitionFrom(Map<String, Object> map) {
MVELRuleDefinition ruleDefinition = new MVELRuleDefinition();
String name = (String) map.get("name");
ruleDefinition.setName(name != null ? name : Rule.DEFAULT_NAME);
String description = (String) map.get("description");
ruleDefinition.setDescription(description != null ? description : Rule.DEFAULT_DESCRIPTION);
Integer priority = (Integer) map.get("priority");
ruleDefinition.setPriority(priority != null ? priority : Rule.DEFAULT_PRIORITY);
String compositeRuleType = (String) map.get("compositeRuleType");
String condition = (String) map.get("condition");
if (condition == null && compositeRuleType == null) {
throw new IllegalArgumentException("The rule condition must be specified");
}
ruleDefinition.setCondition(condition);
List<String> actions = (List<String>) map.get("actions");
if ((actions == null || actions.isEmpty()) && compositeRuleType == null) {
throw new IllegalArgumentException("The rule action(s) must be specified");
}
ruleDefinition.setActions(actions);
List<Object> composingRules = (List<Object>) map.get("composingRules");
if (composingRules != null && compositeRuleType == null) {
throw new IllegalArgumentException("Non-composite rules cannot have composing rules");
} else if (composingRules == null && compositeRuleType != null) {
throw new IllegalArgumentException("Composite rules must have composing rules specified");
} else if (composingRules != null) {
List<MVELRuleDefinition> composingRuleDefinitions = new ArrayList<>();
for (Object rule : composingRules){
Map<String, Object> composingRuleMap = (Map<String, Object>) rule;
composingRuleDefinitions.add(createRuleDefinitionFrom(composingRuleMap));
}
ruleDefinition.setComposingRules(composingRuleDefinitions);
ruleDefinition.setCompositeRuleType(compositeRuleType);
}
/**
* Strategy interface for {@link MVELRuleDefinition} readers.
*
* @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com)
* @see MVELJsonRuleDefinitionReader
* @see MVELYamlRuleDefinitionReader
*/
public interface MVELRuleDefinitionReader {
/**
* Read a list of rule definitions from a rules descriptor.
*
* <strong> The descriptor is expected to contain a collection of rule definitions
* even for a single rule.</strong>
*
* @param reader of the rules descriptor
* @return a list of rule definitions
* @throws Exception if a problem occurs during rule defintion parsing
*/
List<MVELRuleDefinition> read(Reader reader) throws Exception;
return ruleDefinition;
}
}

@ -42,7 +42,10 @@ import java.util.List;
*/
public class MVELRuleFactory {
private static final MVELRuleDefinitionReader READER = new MVELRuleDefinitionReader();
// for backward compatibility only, will be removed in v3.4
private static final MVELRuleDefinitionReader READER = new MVELYamlRuleDefinitionReader();
private MVELRuleDefinitionReader reader;
private static final List<String> ALLOWED_COMPOSITE_RULE_TYPES = Arrays.asList(
UnitRuleGroup.class.getSimpleName(),
@ -50,26 +53,77 @@ public class MVELRuleFactory {
ActivationRuleGroup.class.getSimpleName()
);
/**
* Create a new {@link MVELRuleFactory} with a given reader.
*
* @param reader to use to read rule definitions
* @see MVELYamlRuleDefinitionReader
* @see MVELJsonRuleDefinitionReader
*/
public MVELRuleFactory(MVELRuleDefinitionReader reader) {
this.reader = reader;
}
/**
* Create a new {@link MVELRule} from a Reader.
*
* @param ruleDescriptor as a Reader
* @return a new rule
*/
public static Rule createRuleFrom(Reader ruleDescriptor) {
return createRuleFrom(ruleDescriptor, new ParserContext());
public Rule createRule(Reader ruleDescriptor) throws Exception {
return createRule(ruleDescriptor, new ParserContext());
}
/**
* Create a new {@link MVELRule} from a Reader.
*
* The rule descriptor should contain a single rule definition.
* If no rule definitions are found, a {@link IllegalArgumentException} will be thrown.
* If more than a rule is defined in the descriptor, the first rule will be returned.
*
* @param ruleDescriptor as a Reader
* @param parserContext the MVEL parser context
* @return a new rule
*/
public Rule createRule(Reader ruleDescriptor, ParserContext parserContext) throws Exception {
List<MVELRuleDefinition> ruleDefinitions = reader.read(ruleDescriptor);
if (ruleDefinitions.isEmpty()) {
throw new IllegalArgumentException("rule descriptor is empty");
}
return createRule(ruleDefinitions.get(0), parserContext);
}
/**
* Create a new {@link MVELRule} using a {@link MVELYamlRuleDefinitionReader}.
*
* @param ruleDescriptor as a Reader
* @return a new rule
* @deprecated Use {@link MVELRuleFactory#createRule(java.io.Reader)} instead. This method will be removed in v3.4.
*/
@Deprecated
public static Rule createRuleFrom(Reader ruleDescriptor) throws Exception {
return createRuleFrom(ruleDescriptor, new ParserContext());
}
/**
* Create a new {@link MVELRule} using a {@link MVELYamlRuleDefinitionReader}.
*
* The rule descriptor should contain a single rule definition.
* If no rule definitions are found, a {@link IllegalArgumentException} will be thrown.
* If more than a rule is defined in the descriptor, the first rule will be returned.
*
* @param ruleDescriptor as a Reader
* @param parserContext the MVEL parser context
* @return a new rule
* @deprecated Use {@link MVELRuleFactory#createRule(java.io.Reader, org.mvel2.ParserContext)} instead. This method will be removed in v3.4.
*/
public static Rule createRuleFrom(Reader ruleDescriptor, ParserContext parserContext) {
MVELRuleDefinition ruleDefinition = READER.read(ruleDescriptor);
return createRule(ruleDefinition, parserContext);
@Deprecated
public static Rule createRuleFrom(Reader ruleDescriptor, ParserContext parserContext) throws Exception {
List<MVELRuleDefinition> ruleDefinitions = READER.read(ruleDescriptor);
if (ruleDefinitions.isEmpty()) {
throw new IllegalArgumentException("rule descriptor is empty");
}
return createRule(ruleDefinitions.get(0), parserContext);
}
/**
@ -78,8 +132,8 @@ public class MVELRuleFactory {
* @param rulesDescriptor as a Reader
* @return a set of rules
*/
public static Rules createRulesFrom(Reader rulesDescriptor) {
return createRulesFrom(rulesDescriptor, new ParserContext());
public Rules createRules(Reader rulesDescriptor) throws Exception {
return createRules(rulesDescriptor, new ParserContext());
}
/**
@ -88,9 +142,38 @@ public class MVELRuleFactory {
* @param rulesDescriptor as a Reader
* @return a set of rules
*/
public static Rules createRulesFrom(Reader rulesDescriptor, ParserContext parserContext) {
public Rules createRules(Reader rulesDescriptor, ParserContext parserContext) throws Exception {
Rules rules = new Rules();
List<MVELRuleDefinition> ruleDefinition = reader.read(rulesDescriptor);
for (MVELRuleDefinition mvelRuleDefinition : ruleDefinition) {
rules.register(createRule(mvelRuleDefinition, parserContext));
}
return rules;
}
/**
* Create a set of {@link MVELRule} using a {@link MVELYamlRuleDefinitionReader}.
*
* @param rulesDescriptor as a Reader
* @return a set of rules
* @deprecated Use {@link MVELRuleFactory#createRules(java.io.Reader)} instead. This method will be removed in v3.4.
*/
@Deprecated
public static Rules createRulesFrom(Reader rulesDescriptor) throws Exception {
return createRulesFrom(rulesDescriptor, new ParserContext());
}
/**
* Create a set of {@link MVELRule} using a {@link MVELYamlRuleDefinitionReader}.
*
* @param rulesDescriptor as a Reader
* @return a set of rules
* @deprecated Use {@link MVELRuleFactory#createRules(java.io.Reader, org.mvel2.ParserContext)} instead. This method will be removed in v3.4.
*/
@Deprecated
public static Rules createRulesFrom(Reader rulesDescriptor, ParserContext parserContext) throws Exception {
Rules rules = new Rules();
List<MVELRuleDefinition> ruleDefinition = READER.readAll(rulesDescriptor);
List<MVELRuleDefinition> ruleDefinition = READER.read(rulesDescriptor);
for (MVELRuleDefinition mvelRuleDefinition : ruleDefinition) {
rules.register(createRule(mvelRuleDefinition, parserContext));
}

@ -0,0 +1,121 @@
/**
* The MIT License
*
* Copyright (c) 2019, 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.mvel;
import org.jeasy.rules.api.Rule;
import org.yaml.snakeyaml.Yaml;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Rule definition reader based on <a href="https://github.com/FasterXML/jackson-dataformats-text/tree/master/yaml">Jackson Yaml</a>.
*
* This reader expects a collection of rule definitions as input even for a single rule. For example:
*
* <pre>
* rule1
* ---
* rule2
* </pre>
*
* @author Mahmoud Ben Hassine (mahmoud.benhassine@icloud.com)
*/
@SuppressWarnings("unchecked")
public class MVELYamlRuleDefinitionReader implements MVELRuleDefinitionReader {
private Yaml yaml;
/**
* Create a new {@link MVELYamlRuleDefinitionReader}.
*/
public MVELYamlRuleDefinitionReader() {
yaml = new Yaml();
}
/**
* Create a new {@link MVELYamlRuleDefinitionReader}.
*
* @param yaml to use to read rule definitions
*/
public MVELYamlRuleDefinitionReader(Yaml yaml) {
this.yaml = yaml;
}
public List<MVELRuleDefinition> read(Reader reader) {
List<MVELRuleDefinition> ruleDefinitions = new ArrayList<>();
Iterable<Object> rules = yaml.loadAll(reader);
for (Object rule : rules) {
Map<String, Object> map = (Map<String, Object>) rule;
ruleDefinitions.add(createRuleDefinitionFrom(map));
}
return ruleDefinitions;
}
private MVELRuleDefinition createRuleDefinitionFrom(Map<String, Object> map) {
MVELRuleDefinition ruleDefinition = new MVELRuleDefinition();
String name = (String) map.get("name");
ruleDefinition.setName(name != null ? name : Rule.DEFAULT_NAME);
String description = (String) map.get("description");
ruleDefinition.setDescription(description != null ? description : Rule.DEFAULT_DESCRIPTION);
Integer priority = (Integer) map.get("priority");
ruleDefinition.setPriority(priority != null ? priority : Rule.DEFAULT_PRIORITY);
String compositeRuleType = (String) map.get("compositeRuleType");
String condition = (String) map.get("condition");
if (condition == null && compositeRuleType == null) {
throw new IllegalArgumentException("The rule condition must be specified");
}
ruleDefinition.setCondition(condition);
List<String> actions = (List<String>) map.get("actions");
if ((actions == null || actions.isEmpty()) && compositeRuleType == null) {
throw new IllegalArgumentException("The rule action(s) must be specified");
}
ruleDefinition.setActions(actions);
List<Object> composingRules = (List<Object>) map.get("composingRules");
if (composingRules != null && compositeRuleType == null) {
throw new IllegalArgumentException("Non-composite rules cannot have composing rules");
} else if (composingRules == null && compositeRuleType != null) {
throw new IllegalArgumentException("Composite rules must have composing rules specified");
} else if (composingRules != null) {
List<MVELRuleDefinition> composingRuleDefinitions = new ArrayList<>();
for (Object rule : composingRules){
Map<String, Object> composingRuleMap = (Map<String, Object>) rule;
composingRuleDefinitions.add(createRuleDefinitionFrom(composingRuleMap));
}
ruleDefinition.setComposingRules(composingRuleDefinitions);
ruleDefinition.setCompositeRuleType(compositeRuleType);
}
return ruleDefinition;
}
}

@ -0,0 +1,205 @@
/**
* The MIT License
*
* Copyright (c) 2019, 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.mvel;
import org.jeasy.rules.api.Rule;
import org.junit.Test;
import java.io.File;
import java.io.FileReader;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
// TODO use parametrized test to merge this test class with MVELYamlRuleDefinitionReaderTest
public class MVELJsonRuleDefinitionReaderTest {
private MVELRuleDefinitionReader ruleDefinitionReader = new MVELJsonRuleDefinitionReader();
@Test
public void testRuleDefinitionReadingFromFile() throws Exception {
// given
File adultRuleDescriptor = new File("src/test/resources/adult-rule.json");
// when
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
// then
assertThat(ruleDefinitions).hasSize(1);
MVELRuleDefinition adultRuleDefinition = ruleDefinitions.get(0);
assertThat(adultRuleDefinition).isNotNull();
assertThat(adultRuleDefinition.getName()).isEqualTo("adult rule");
assertThat(adultRuleDefinition.getDescription()).isEqualTo("when age is greater then 18, then mark as adult");
assertThat(adultRuleDefinition.getPriority()).isEqualTo(1);
assertThat(adultRuleDefinition.getCondition()).isEqualTo("person.age > 18");
assertThat(adultRuleDefinition.getActions()).isEqualTo(Collections.singletonList("person.setAdult(true);"));
}
@Test
public void testRuleDefinitionReadingFromString() throws Exception {
// given
String adultRuleDescriptor = new String(Files.readAllBytes(Paths.get("src/test/resources/adult-rule.json")));
// when
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new StringReader(adultRuleDescriptor));
// then
assertThat(ruleDefinitions).hasSize(1);
MVELRuleDefinition adultRuleDefinition = ruleDefinitions.get(0);
assertThat(adultRuleDefinition).isNotNull();
assertThat(adultRuleDefinition.getName()).isEqualTo("adult rule");
assertThat(adultRuleDefinition.getDescription()).isEqualTo("when age is greater then 18, then mark as adult");
assertThat(adultRuleDefinition.getPriority()).isEqualTo(1);
assertThat(adultRuleDefinition.getCondition()).isEqualTo("person.age > 18");
assertThat(adultRuleDefinition.getActions()).isEqualTo(Collections.singletonList("person.setAdult(true);"));
}
@Test
public void testRuleDefinitionReading_withDefaultValues() throws Exception {
// given
File adultRuleDescriptor = new File("src/test/resources/adult-rule-with-default-values.json");
// when
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
// then
assertThat(ruleDefinitions).hasSize(1);
MVELRuleDefinition adultRuleDefinition = ruleDefinitions.get(0);
assertThat(adultRuleDefinition).isNotNull();
assertThat(adultRuleDefinition.getName()).isEqualTo(Rule.DEFAULT_NAME);
assertThat(adultRuleDefinition.getDescription()).isEqualTo(Rule.DEFAULT_DESCRIPTION);
assertThat(adultRuleDefinition.getPriority()).isEqualTo(Rule.DEFAULT_PRIORITY);
assertThat(adultRuleDefinition.getCondition()).isEqualTo("person.age > 18");
assertThat(adultRuleDefinition.getActions()).isEqualTo(Collections.singletonList("person.setAdult(true);"));
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidRuleDefinitionReading_whenNoCondition() throws Exception {
// given
File adultRuleDescriptor = new File("src/test/resources/adult-rule-without-condition.json");
// when
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
// then
// expected exception
}
@Test(expected = IllegalArgumentException.class)
public void testInvalidRuleDefinitionReading_whenNoActions() throws Exception {
// given
File adultRuleDescriptor = new File("src/test/resources/adult-rule-without-actions.json");
// when
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
// then
// expected exception
}
@Test
public void testRulesDefinitionReading() throws Exception {
// given
File rulesDescriptor = new File("src/test/resources/rules.json");
// when
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(rulesDescriptor));
// then
assertThat(ruleDefinitions).hasSize(2);
MVELRuleDefinition ruleDefinition = ruleDefinitions.get(0);
assertThat(ruleDefinition).isNotNull();
assertThat(ruleDefinition.getName()).isEqualTo("adult rule");
assertThat(ruleDefinition.getDescription()).isEqualTo("when age is greater then 18, then mark as adult");
assertThat(ruleDefinition.getPriority()).isEqualTo(1);
assertThat(ruleDefinition.getCondition()).isEqualTo("person.age > 18");
assertThat(ruleDefinition.getActions()).isEqualTo(Collections.singletonList("person.setAdult(true);"));
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.getPriority()).isEqualTo(2);
assertThat(ruleDefinition.getCondition()).isEqualTo("rain == true");
assertThat(ruleDefinition.getActions()).isEqualTo(Collections.singletonList("System.out.println(\"It rains, take an umbrella!\");"));
}
@Test
public void testEmptyRulesDefinitionReading() throws Exception {
// given
File rulesDescriptor = new File("src/test/resources/rules-empty.json");
// when
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(rulesDescriptor));
// then
assertThat(ruleDefinitions).hasSize(0);
}
@Test
public void testRuleDefinitionReading_withCompositeAndBasicRules() throws Exception {
// given
File compositeRuleDescriptor = new File("src/test/resources/composite-rules.json");
// when
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(compositeRuleDescriptor));
// then
assertThat(ruleDefinitions).hasSize(2);
// then
MVELRuleDefinition ruleDefinition = ruleDefinitions.get(0);
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();
List<MVELRuleDefinition> subrules = ruleDefinition.getComposingRules();
assertThat(subrules).hasSize(2);
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()).isEmpty();
assertThat(ruleDefinition.getCondition()).isEqualTo("rain == True");
assertThat(ruleDefinition.getActions()).isEqualTo(Collections.singletonList("System.out.println(\"It rains, take an umbrella!\");"));
}
}

@ -0,0 +1,170 @@
/**
* The MIT License
*
* Copyright (c) 2019, 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.mvel;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.support.UnitRuleGroup;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Iterator;
import static org.assertj.core.api.Assertions.assertThat;
// TODO use parametrized test to merge this test class with MVELYamlRuleFactoryTest
public class MVELJsonRuleFactoryTest {
@org.junit.Rule
public ExpectedException expectedException = ExpectedException.none();
private MVELRuleFactory factory = new MVELRuleFactory(new MVELJsonRuleDefinitionReader());
@Test
public void testRulesCreation() throws Exception {
// given
File rulesDescriptor = new File("src/test/resources/rules.json");
// when
Rules rules = factory.createRules(new FileReader(rulesDescriptor));
// then
assertThat(rules).hasSize(2);
Iterator<Rule> iterator = rules.iterator();
Rule rule = iterator.next();
assertThat(rule).isNotNull();
assertThat(rule.getName()).isEqualTo("adult rule");
assertThat(rule.getDescription()).isEqualTo("when age is greater then 18, then mark as adult");
assertThat(rule.getPriority()).isEqualTo(1);
rule = iterator.next();
assertThat(rule).isNotNull();
assertThat(rule.getName()).isEqualTo("weather rule");
assertThat(rule.getDescription()).isEqualTo("when it rains, then take an umbrella");
assertThat(rule.getPriority()).isEqualTo(2);
}
@Test
public void testRuleCreationFromFileReader() throws Exception{
// given
Reader adultRuleDescriptorAsReader = new FileReader("src/test/resources/adult-rule.json");
// when
Rule adultRule = factory.createRule(adultRuleDescriptorAsReader);
// then
assertThat(adultRule.getName()).isEqualTo("adult rule");
assertThat(adultRule.getDescription()).isEqualTo("when age is greater then 18, then mark as adult");
assertThat(adultRule.getPriority()).isEqualTo(1);
}
@Test
public void testRuleCreationFromStringReader() throws Exception{
// given
Reader adultRuleDescriptorAsReader = new StringReader(new String(Files.readAllBytes(Paths.get("src/test/resources/adult-rule.json"))));
// when
Rule adultRule = factory.createRule(adultRuleDescriptorAsReader);
// then
assertThat(adultRule.getName()).isEqualTo("adult rule");
assertThat(adultRule.getDescription()).isEqualTo("when age is greater then 18, then mark as adult");
assertThat(adultRule.getPriority()).isEqualTo(1);
}
@Test
public void testRuleCreationFromFileReader_withCompositeRules() throws Exception {
// given
File rulesDescriptor = new File("src/test/resources/composite-rules.json");
// when
Rules rules = factory.createRules(new FileReader(rulesDescriptor));
// then
assertThat(rules).hasSize(2);
Iterator<Rule> iterator = rules.iterator();
Rule rule = iterator.next();
assertThat(rule).isNotNull();
assertThat(rule.getName()).isEqualTo("Movie id rule");
assertThat(rule.getDescription()).isEqualTo("description");
assertThat(rule.getPriority()).isEqualTo(1);
assertThat(rule).isInstanceOf(UnitRuleGroup.class);
rule = iterator.next();
assertThat(rule).isNotNull();
assertThat(rule.getName()).isEqualTo("weather rule");
assertThat(rule.getDescription()).isEqualTo("when it rains, then take an umbrella");
assertThat(rule.getPriority()).isEqualTo(1);;
}
@Test
public void testRuleCreationFromFileReader_withInvalidCompositeRuleType() throws Exception {
// given
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Invalid composite rule type, must be one of [UnitRuleGroup, ConditionalRuleGroup, ActivationRuleGroup]");
File rulesDescriptor = new File("src/test/resources/composite-rule-invalid-composite-rule-type.json");
// when
Rule rule = factory.createRule(new FileReader(rulesDescriptor));
// then
// expected exception
}
@Test
public void testRuleCreationFromFileReader_withEmptyComposingRules() throws Exception {
// given
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Composite rules must have composing rules specified");
File rulesDescriptor = new File("src/test/resources/composite-rule-invalid-empty-composing-rules.json");
// when
Rule rule = factory.createRule(new FileReader(rulesDescriptor));
// then
// expected exception
}
@Test
public void testRuleCreationFromFileReader_withNonCompositeRuleDeclaresComposingRules() throws Exception {
// given
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Non-composite rules cannot have composing rules");
File rulesDescriptor = new File("src/test/resources/non-composite-rule-with-composing-rules.json");
// when
Rule rule = factory.createRule(new FileReader(rulesDescriptor));
// then
// expected exception
}
}

@ -24,7 +24,6 @@
package org.jeasy.rules.mvel;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.Rules;
import org.junit.Test;
import java.io.File;
@ -33,14 +32,14 @@ import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class MVELRuleDefinitionReaderTest {
// TODO use parametrized test to merge this test class with MVELJsonRuleDefinitionReaderTest
public class MVELYamlRuleDefinitionReaderTest {
private MVELRuleDefinitionReader ruleDefinitionReader = new MVELRuleDefinitionReader();
private MVELRuleDefinitionReader ruleDefinitionReader = new MVELYamlRuleDefinitionReader();
@Test
public void testRuleDefinitionReadingFromFile() throws Exception {
@ -48,9 +47,11 @@ public class MVELRuleDefinitionReaderTest {
File adultRuleDescriptor = new File("src/test/resources/adult-rule.yml");
// when
MVELRuleDefinition adultRuleDefinition = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
// then
assertThat(ruleDefinitions).hasSize(1);
MVELRuleDefinition adultRuleDefinition = ruleDefinitions.get(0);
assertThat(adultRuleDefinition).isNotNull();
assertThat(adultRuleDefinition.getName()).isEqualTo("adult rule");
assertThat(adultRuleDefinition.getDescription()).isEqualTo("when age is greater then 18, then mark as adult");
@ -65,9 +66,11 @@ public class MVELRuleDefinitionReaderTest {
String adultRuleDescriptor = new String(Files.readAllBytes(Paths.get("src/test/resources/adult-rule.yml")));
// when
MVELRuleDefinition adultRuleDefinition = ruleDefinitionReader.read(new StringReader(adultRuleDescriptor));
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new StringReader(adultRuleDescriptor));
// then
assertThat(ruleDefinitions).hasSize(1);
MVELRuleDefinition adultRuleDefinition = ruleDefinitions.get(0);
assertThat(adultRuleDefinition).isNotNull();
assertThat(adultRuleDefinition.getName()).isEqualTo("adult rule");
assertThat(adultRuleDefinition.getDescription()).isEqualTo("when age is greater then 18, then mark as adult");
@ -82,9 +85,11 @@ public class MVELRuleDefinitionReaderTest {
File adultRuleDescriptor = new File("src/test/resources/adult-rule-with-default-values.yml");
// when
MVELRuleDefinition adultRuleDefinition = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
// then
assertThat(ruleDefinitions).hasSize(1);
MVELRuleDefinition adultRuleDefinition = ruleDefinitions.get(0);
assertThat(adultRuleDefinition).isNotNull();
assertThat(adultRuleDefinition.getName()).isEqualTo(Rule.DEFAULT_NAME);
assertThat(adultRuleDefinition.getDescription()).isEqualTo(Rule.DEFAULT_DESCRIPTION);
@ -99,7 +104,7 @@ public class MVELRuleDefinitionReaderTest {
File adultRuleDescriptor = new File("src/test/resources/adult-rule-without-condition.yml");
// when
MVELRuleDefinition adultRuleDefinition = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
// then
// expected exception
@ -111,7 +116,7 @@ public class MVELRuleDefinitionReaderTest {
File adultRuleDescriptor = new File("src/test/resources/adult-rule-without-actions.yml");
// when
MVELRuleDefinition adultRuleDefinition = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(adultRuleDescriptor));
// then
// expected exception
@ -123,7 +128,7 @@ public class MVELRuleDefinitionReaderTest {
File rulesDescriptor = new File("src/test/resources/rules.yml");
// when
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.readAll(new FileReader(rulesDescriptor));
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(rulesDescriptor));
// then
assertThat(ruleDefinitions).hasSize(2);
@ -150,7 +155,7 @@ public class MVELRuleDefinitionReaderTest {
File rulesDescriptor = new File("src/test/resources/rules-empty.yml");
// when
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.readAll(new FileReader(rulesDescriptor));
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(rulesDescriptor));
// then
assertThat(ruleDefinitions).hasSize(0);
@ -159,10 +164,10 @@ public class MVELRuleDefinitionReaderTest {
@Test
public void testRuleDefinitionReading_withCompositeAndBasicRules() throws Exception {
// given
File compositeRuleDescriptor = new File("src/test/resources/composite-rule.yml");
File compositeRuleDescriptor = new File("src/test/resources/composite-rules.yml");
// when
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.readAll(new FileReader(compositeRuleDescriptor));
List<MVELRuleDefinition> ruleDefinitions = ruleDefinitionReader.read(new FileReader(compositeRuleDescriptor));
// then
assertThat(ruleDefinitions).hasSize(2);

@ -39,18 +39,21 @@ import java.util.Iterator;
import static org.assertj.core.api.Assertions.assertThat;
public class MVELRuleFactoryTest {
// TODO use parametrized test to merge this test class with MVELJsonRuleFactoryTest
public class MVELYamlRuleFactoryTest {
@org.junit.Rule
public ExpectedException expectedException = ExpectedException.none();
private MVELRuleFactory factory = new MVELRuleFactory(new MVELYamlRuleDefinitionReader());
@Test
public void testRulesCreation() throws Exception {
// given
File rulesDescriptor = new File("src/test/resources/rules.yml");
// when
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader(rulesDescriptor));
Rules rules = factory.createRules(new FileReader(rulesDescriptor));
// then
assertThat(rules).hasSize(2);
@ -75,7 +78,7 @@ public class MVELRuleFactoryTest {
Reader adultRuleDescriptorAsReader = new FileReader("src/test/resources/adult-rule.yml");
// when
Rule adultRule = MVELRuleFactory.createRuleFrom(adultRuleDescriptorAsReader);
Rule adultRule = factory.createRule(adultRuleDescriptorAsReader);
// then
assertThat(adultRule.getName()).isEqualTo("adult rule");
@ -89,7 +92,7 @@ public class MVELRuleFactoryTest {
Reader adultRuleDescriptorAsReader = new StringReader(new String(Files.readAllBytes(Paths.get("src/test/resources/adult-rule.yml"))));
// when
Rule adultRule = MVELRuleFactory.createRuleFrom(adultRuleDescriptorAsReader);
Rule adultRule = factory.createRule(adultRuleDescriptorAsReader);
// then
assertThat(adultRule.getName()).isEqualTo("adult rule");
@ -100,10 +103,10 @@ public class MVELRuleFactoryTest {
@Test
public void testRuleCreationFromFileReader_withCompositeRules() throws Exception {
// given
File rulesDescriptor = new File("src/test/resources/composite-rule.yml");
File rulesDescriptor = new File("src/test/resources/composite-rules.yml");
// when
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader(rulesDescriptor));
Rules rules = factory.createRules(new FileReader(rulesDescriptor));
// then
assertThat(rules).hasSize(2);
@ -131,7 +134,7 @@ public class MVELRuleFactoryTest {
File rulesDescriptor = new File("src/test/resources/composite-rule-invalid-composite-rule-type.yml");
// when
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader(rulesDescriptor));
Rule rule = factory.createRule(new FileReader(rulesDescriptor));
// then
// expected exception
@ -145,7 +148,7 @@ public class MVELRuleFactoryTest {
File rulesDescriptor = new File("src/test/resources/composite-rule-invalid-empty-composing-rules.yml");
// when
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader(rulesDescriptor));
Rule rule = factory.createRule(new FileReader(rulesDescriptor));
// then
// expected exception
@ -159,7 +162,7 @@ public class MVELRuleFactoryTest {
File rulesDescriptor = new File("src/test/resources/non-composite-rule-with-composing-rules.yml");
// when
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader(rulesDescriptor));
Rule rule = factory.createRule(new FileReader(rulesDescriptor));
// then
// expected exception

@ -0,0 +1,8 @@
[
{
"condition": "person.age > 18",
"actions": [
"person.setAdult(true);"
]
}
]

@ -0,0 +1,5 @@
[
{
"condition": "person.age > 18"
}
]

@ -0,0 +1,7 @@
[
{
"actions": [
"person.setAdult(true);"
]
}
]

@ -0,0 +1,11 @@
[
{
"name": "adult rule",
"description": "when age is greater then 18, then mark as adult",
"priority": 1,
"condition": "person.age > 18",
"actions": [
"person.setAdult(true);"
]
}
]

@ -0,0 +1,23 @@
[
{
"name": "invalid rule",
"compositeRuleType": "foo",
"priority": 1,
"composingRules": [
{
"name": "rule1",
"condition": "true",
"actions": [
"System.out.println();"
]
},
{
"name": "rule2",
"condition": "false",
"actions": [
"System.out.println();"
]
}
]
}
]

@ -0,0 +1,8 @@
[
{
"name": "invalid rule",
"compositeRuleType": "UnitRuleGroup",
"priority": 1,
"composingRules": []
}
]

@ -0,0 +1,36 @@
[
{
"name": "Movie id rule",
"compositeRuleType": "UnitRuleGroup",
"priority": 1,
"composingRules": [
{
"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!\");"
]
}
]

@ -0,0 +1,30 @@
[
{
"name": "Movie id rule",
"priority": 1,
"condition": "true",
"actions": [
"System.out.println();"
],
"composingRules": [
{
"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);"
]
}
]
}
]

@ -0,0 +1,20 @@
[
{
"name": "adult rule",
"description": "when age is greater then 18, then mark as adult",
"priority": 1,
"condition": "person.age > 18",
"actions": [
"person.setAdult(true);"
]
},
{
"name": "weather rule",
"description": "when it rains, then take an umbrella",
"priority": 2,
"condition": "rain == true",
"actions": [
"System.out.println(\"It rains, take an umbrella!\");"
]
}
]

@ -30,13 +30,13 @@ import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.mvel.MVELRule;
import org.jeasy.rules.mvel.MVELRuleFactory;
import org.jeasy.rules.mvel.MVELYamlRuleDefinitionReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class Launcher {
public static void main(String[] args) throws FileNotFoundException {
public static void main(String[] args) throws Exception {
//create a person instance (fact)
Person tom = new Person("Tom", 14);
Facts facts = new Facts();
@ -49,7 +49,8 @@ public class Launcher {
.priority(1)
.when("person.age > 18")
.then("person.setAdult(true);");
Rule alcoholRule = MVELRuleFactory.createRuleFrom(new FileReader("src/main/java/org/jeasy/rules/tutorials/shop/alcohol-rule.yml"));
MVELRuleFactory ruleFactory = new MVELRuleFactory(new MVELYamlRuleDefinitionReader());
Rule alcoholRule = ruleFactory.createRule(new FileReader("src/main/java/org/jeasy/rules/tutorials/shop/alcohol-rule.yml"));
// create a rule set
Rules rules = new Rules();

Loading…
Cancel
Save