NIFI-6890 Support configuring rules in controller service configuration

Signed-off-by: Matthew Burgess <mattyb149@apache.org>

This closes #3902
This commit is contained in:
Yolanda M. Davis 2019-11-21 17:25:28 -05:00 committed by Matthew Burgess
parent 5cfc68d26d
commit 58130485a3
No known key found for this signature in database
GPG Key ID: 05D3DEB8126DAD24
5 changed files with 211 additions and 36 deletions

View File

@ -25,10 +25,9 @@ import org.jeasy.rules.support.YamlRuleDefinitionReader;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.constructor.Constructor;
import java.io.File; import java.io.ByteArrayInputStream;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.ArrayList; import java.util.ArrayList;
@ -51,25 +50,36 @@ public class RulesFactory {
NIFI, MVEL, SPEL; NIFI, MVEL, SPEL;
} }
public static List<Rule> createRules(String ruleFile, String ruleFileType, String rulesFileFormat) throws Exception{ public static List<Rule> createRulesFromFile(String ruleFile, String ruleFileType, String rulesFileFormat) throws Exception {
InputStream rulesInputStream = new FileInputStream(ruleFile);
return createRules(rulesInputStream, ruleFileType, rulesFileFormat);
}
public static List<Rule> createRulesFromString(String rulesBody, String ruleFileType, String rulesFileFormat) throws Exception {
InputStream rulesInputStream = new ByteArrayInputStream(rulesBody.getBytes());
return createRules(rulesInputStream, ruleFileType, rulesFileFormat);
}
private static List<Rule> createRules(InputStream rulesInputStream, String ruleFileType, String rulesFileFormat) throws Exception {
FileFormat fileFormat = FileFormat.valueOf(rulesFileFormat); FileFormat fileFormat = FileFormat.valueOf(rulesFileFormat);
switch (fileFormat){ switch (fileFormat) {
case NIFI: case NIFI:
return createRulesFromNiFiFormat(ruleFile, ruleFileType); return createRulesFromNiFiFormat(rulesInputStream, ruleFileType);
case MVEL: case MVEL:
case SPEL: case SPEL:
return createRulesFromEasyRulesFormat(ruleFile, ruleFileType, rulesFileFormat); return createRulesFromEasyRulesFormat(rulesInputStream, ruleFileType, rulesFileFormat);
default: default:
return null; return null;
} }
} }
private static List<Rule> createRulesFromEasyRulesFormat(String ruleFile, String ruleFileType, String ruleFileFormat) throws Exception{ private static List<Rule> createRulesFromEasyRulesFormat(InputStream rulesInputStream, String ruleFileType, String ruleFileFormat) throws Exception {
RuleDefinitionReader reader = FileType.valueOf(ruleFileType).equals(FileType.YAML) RuleDefinitionReader reader = FileType.valueOf(ruleFileType).equals(FileType.YAML)
? new YamlRuleDefinitionReader() : new JsonRuleDefinitionReader(); ? new YamlRuleDefinitionReader() : new JsonRuleDefinitionReader();
List<RuleDefinition> ruleDefinitions = reader.read(new FileReader(ruleFile)); List<RuleDefinition> ruleDefinitions = reader.read(new InputStreamReader(rulesInputStream));
return ruleDefinitions.stream().map(ruleDefinition -> { return ruleDefinitions.stream().map(ruleDefinition -> {
@ -81,7 +91,7 @@ public class RulesFactory {
List<Action> actions = ruleDefinition.getActions().stream().map(ruleAction -> { List<Action> actions = ruleDefinition.getActions().stream().map(ruleAction -> {
Action action = new Action(); Action action = new Action();
action.setType("EXPRESSION"); action.setType("EXPRESSION");
Map<String,String> attributes = new HashMap<>(); Map<String, String> attributes = new HashMap<>();
attributes.put("command", ruleAction); attributes.put("command", ruleAction);
attributes.put("type", ruleFileFormat); attributes.put("type", ruleFileFormat);
action.setAttributes(attributes); action.setAttributes(attributes);
@ -93,23 +103,21 @@ public class RulesFactory {
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} }
private static List<Rule> createRulesFromNiFiFormat(String ruleFile, String ruleFileType) throws Exception{ private static List<Rule> createRulesFromNiFiFormat(InputStream rulesInputStream, String ruleFileType) throws Exception {
FileType type = FileType.valueOf(ruleFileType.toUpperCase()); FileType type = FileType.valueOf(ruleFileType.toUpperCase());
if (type.equals(FileType.YAML)) { if (type.equals(FileType.YAML)) {
return yamlToRules(ruleFile); return yamlToRules(rulesInputStream);
} else if (type.equals(FileType.JSON)) { } else if (type.equals(FileType.JSON)) {
return jsonToRules(ruleFile); return jsonToRules(rulesInputStream);
} else { } else {
return null; return null;
} }
} }
private static List<Rule> yamlToRules(String rulesFile) throws FileNotFoundException { private static List<Rule> yamlToRules(InputStream rulesInputStream) throws FileNotFoundException {
List<Rule> rules = new ArrayList<>(); List<Rule> rules = new ArrayList<>();
Yaml yaml = new Yaml(new Constructor(Rule.class)); Yaml yaml = new Yaml(new Constructor(Rule.class));
File yamlFile = new File(rulesFile); for (Object object : yaml.loadAll(rulesInputStream)) {
InputStream inputStream = new FileInputStream(yamlFile);
for (Object object : yaml.loadAll(inputStream)) {
if (object instanceof Rule) { if (object instanceof Rule) {
rules.add((Rule) object); rules.add((Rule) object);
} }
@ -117,11 +125,12 @@ public class RulesFactory {
return rules; return rules;
} }
private static List<Rule> jsonToRules(String rulesFile) throws Exception { private static List<Rule> jsonToRules(InputStream rulesInputStream) throws Exception {
List<Rule> rules; List<Rule> rules;
InputStreamReader isr = new InputStreamReader(new FileInputStream(rulesFile)); InputStreamReader isr = new InputStreamReader(rulesInputStream);
final ObjectMapper objectMapper = new ObjectMapper(); final ObjectMapper objectMapper = new ObjectMapper();
rules = objectMapper.readValue(isr, new TypeReference<List<Rule>>(){}); rules = objectMapper.readValue(isr, new TypeReference<List<Rule>>() {
});
return rules; return rules;
} }
} }

View File

@ -21,6 +21,9 @@ import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.annotation.lifecycle.OnEnabled; import org.apache.nifi.annotation.lifecycle.OnEnabled;
import org.apache.nifi.components.AllowableValue; import org.apache.nifi.components.AllowableValue;
import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.Validator;
import org.apache.nifi.controller.AbstractControllerService; import org.apache.nifi.controller.AbstractControllerService;
import org.apache.nifi.controller.ConfigurationContext; import org.apache.nifi.controller.ConfigurationContext;
import org.apache.nifi.controller.ControllerServiceInitializationContext; import org.apache.nifi.controller.ControllerServiceInitializationContext;
@ -33,6 +36,7 @@ import org.apache.nifi.rules.Rule;
import org.apache.nifi.rules.RulesFactory; import org.apache.nifi.rules.RulesFactory;
import org.apache.nifi.rules.RulesMVELCondition; import org.apache.nifi.rules.RulesMVELCondition;
import org.apache.nifi.rules.RulesSPELCondition; import org.apache.nifi.rules.RulesSPELCondition;
import org.apache.nifi.util.StringUtils;
import org.jeasy.rules.api.Condition; import org.jeasy.rules.api.Condition;
import org.jeasy.rules.api.Facts; import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.RuleListener; import org.jeasy.rules.api.RuleListener;
@ -41,9 +45,12 @@ import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.core.RuleBuilder; import org.jeasy.rules.core.RuleBuilder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* Implementation of RulesEngineService interface * Implementation of RulesEngineService interface
@ -64,16 +71,25 @@ public class EasyRulesEngineService extends AbstractControllerService implement
static final PropertyDescriptor RULES_FILE_PATH = new PropertyDescriptor.Builder() static final PropertyDescriptor RULES_FILE_PATH = new PropertyDescriptor.Builder()
.name("rules-file-path") .name("rules-file-path")
.displayName("Rules File Path") .displayName("Rules File Path")
.description("Path to location of rules file.") .description("Path to location of rules file. Only one of Rules File or Rules Body may be used")
.required(true) .required(false)
.addValidator(StandardValidators.FILE_EXISTS_VALIDATOR) .addValidator(StandardValidators.FILE_EXISTS_VALIDATOR)
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY) .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build(); .build();
static final PropertyDescriptor RULES_BODY = new PropertyDescriptor.Builder()
.name("rules-body")
.displayName("Rules Body")
.description("Body of rules file to execute. Only one of Rules File or Rules Body may be used")
.required(false)
.addValidator(Validator.VALID)
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
static final PropertyDescriptor RULES_FILE_TYPE = new PropertyDescriptor.Builder() static final PropertyDescriptor RULES_FILE_TYPE = new PropertyDescriptor.Builder()
.name("rules-file-type") .name("rules-file-type")
.displayName("Rules File Type") .displayName("Rules File Type")
.description("File type for rules definition. Supported file types are YAML and JSON") .description("File or Body type for rules definition. Supported types are YAML and JSON")
.required(true) .required(true)
.allowableValues(JSON,YAML) .allowableValues(JSON,YAML)
.defaultValue(JSON.getValue()) .defaultValue(JSON.getValue())
@ -82,7 +98,7 @@ public class EasyRulesEngineService extends AbstractControllerService implement
static final PropertyDescriptor RULES_FILE_FORMAT = new PropertyDescriptor.Builder() static final PropertyDescriptor RULES_FILE_FORMAT = new PropertyDescriptor.Builder()
.name("rules-file-format") .name("rules-file-format")
.displayName("Rules File Format") .displayName("Rules File Format")
.description("File format for rules. Supported formats are NiFi Rules, Easy Rules files with MVEL Expression Language" + .description("Format for rules. Supported formats are NiFi Rules, Easy Rules files with MVEL Expression Language" +
" and Easy Rules files with Spring Expression Language.") " and Easy Rules files with Spring Expression Language.")
.required(true) .required(true)
.allowableValues(NIFI,MVEL,SPEL) .allowableValues(NIFI,MVEL,SPEL)
@ -111,6 +127,7 @@ public class EasyRulesEngineService extends AbstractControllerService implement
final List<PropertyDescriptor> properties = new ArrayList<>(); final List<PropertyDescriptor> properties = new ArrayList<>();
properties.add(RULES_FILE_TYPE); properties.add(RULES_FILE_TYPE);
properties.add(RULES_FILE_PATH); properties.add(RULES_FILE_PATH);
properties.add(RULES_BODY);
properties.add(RULES_FILE_FORMAT); properties.add(RULES_FILE_FORMAT);
properties.add(IGNORE_CONDITION_ERRORS); properties.add(IGNORE_CONDITION_ERRORS);
this.properties = Collections.unmodifiableList(properties); this.properties = Collections.unmodifiableList(properties);
@ -124,16 +141,44 @@ public class EasyRulesEngineService extends AbstractControllerService implement
@OnEnabled @OnEnabled
public void onEnabled(final ConfigurationContext context) throws InitializationException { public void onEnabled(final ConfigurationContext context) throws InitializationException {
final String rulesFile = context.getProperty(RULES_FILE_PATH).getValue(); final String rulesFile = context.getProperty(RULES_FILE_PATH).getValue();
final String rulesBody = context.getProperty(RULES_BODY).getValue();
final String rulesFileType = context.getProperty(RULES_FILE_TYPE).getValue(); final String rulesFileType = context.getProperty(RULES_FILE_TYPE).getValue();
rulesFileFormat = context.getProperty(RULES_FILE_FORMAT).getValue(); rulesFileFormat = context.getProperty(RULES_FILE_FORMAT).getValue();
ignoreConditionErrors = context.getProperty(IGNORE_CONDITION_ERRORS).asBoolean(); ignoreConditionErrors = context.getProperty(IGNORE_CONDITION_ERRORS).asBoolean();
try{ try{
rules = RulesFactory.createRules(rulesFile, rulesFileType, rulesFileFormat); if(StringUtils.isEmpty(rulesFile)){
rules = RulesFactory.createRulesFromString(rulesBody, rulesFileType, rulesFileFormat);
}else{
rules = RulesFactory.createRulesFromFile(rulesFile, rulesFileType, rulesFileFormat);
}
} catch (Exception fex){ } catch (Exception fex){
throw new InitializationException(fex); throw new InitializationException(fex);
} }
} }
/**
* Custom validation for ensuring exactly one of Script File or Script Body is populated
*
* @param validationContext provides a mechanism for obtaining externally
* managed values, such as property values and supplies convenience methods
* for operating on those values
* @return A collection of validation results
*/
@Override
public Collection<ValidationResult> customValidate(ValidationContext validationContext) {
Set<ValidationResult> results = new HashSet<>();
// Verify that exactly one of "script file" or "script body" is set
Map<PropertyDescriptor, String> propertyMap = validationContext.getProperties();
if (StringUtils.isEmpty(propertyMap.get(RULES_FILE_PATH)) == StringUtils.isEmpty(propertyMap.get(RULES_BODY))) {
results.add(new ValidationResult.Builder().subject("Rules Body or Rules File").valid(false).explanation(
"exactly one of Rules File or Rules Body must be set").build());
}
return results;
}
/** /**
* Return the list of actions what should be executed for a given set of facts * Return the list of actions what should be executed for a given set of facts
* @param facts a Map of key and facts values, as objects, that should be evaluated by the rules engine * @param facts a Map of key and facts values, as objects, that should be evaluated by the rules engine

View File

@ -21,11 +21,11 @@
</head> </head>
<body> <body>
<h2>General</h2> <h2>General</h2>
<p>The Easy Rules Engine Service supports execution of a centralized set of rules (stored as files) against a provided set of data called facts. Facts sent to the service are processed against <p>The Easy Rules Engine Service supports execution of a centralized set of rules (stored as files or provided within the service configuration) against a provided set of data called facts. Facts sent to the service are processed against
the rules engine to determine what, if any, actions should be executed based on the conditions defined within the rules. The list of actions are returned to the caller to handle as needed. the rules engine to determine what, if any, actions should be executed based on the conditions defined within the rules. The list of actions are returned to the caller to handle as needed.
</p> </p>
<p> <p>
Rules files can be implemented in any of the following formats: Rules can be implemented in any of the following formats:
</p> </p>
<ul> <ul>
<li> NiFi Rules Format - This is a rules file which follows the NiFi style for rules definition, which supports MVEL (MVFLEX) Expression language for conditions (default format). <li> NiFi Rules Format - This is a rules file which follows the NiFi style for rules definition, which supports MVEL (MVFLEX) Expression language for conditions (default format).
@ -36,7 +36,7 @@
</li> </li>
</ul> </ul>
<p> <p>
All rules formats can be implemented as JSON or YAML files (with JSON serving as default file type). All rules formats can be structured as JSON or YAML (with JSON serving as default type). Rules can be stored as a file or provided in the Rules Body setting in the service's configuration settings.
</p> </p>
<p> <p>

View File

@ -29,7 +29,7 @@ public class TestRulesFactory {
public void testCreateRulesFromNiFiYaml(){ public void testCreateRulesFromNiFiYaml(){
try { try {
String testYamlFile = "src/test/resources/test_nifi_rules.yml"; String testYamlFile = "src/test/resources/test_nifi_rules.yml";
List<Rule> rules = RulesFactory.createRules(testYamlFile,"YAML", "NIFI"); List<Rule> rules = RulesFactory.createRulesFromFile(testYamlFile,"YAML", "NIFI");
assertEquals(2, rules.size()); assertEquals(2, rules.size());
assert confirmEntries(rules); assert confirmEntries(rules);
}catch (Exception ex){ }catch (Exception ex){
@ -41,7 +41,7 @@ public class TestRulesFactory {
public void testCreateRulesFromMvelYaml(){ public void testCreateRulesFromMvelYaml(){
try { try {
String testYamlFile = "src/test/resources/test_mvel_rules.yml"; String testYamlFile = "src/test/resources/test_mvel_rules.yml";
List<Rule> rules = RulesFactory.createRules(testYamlFile,"YAML", "MVEL"); List<Rule> rules = RulesFactory.createRulesFromFile(testYamlFile,"YAML", "MVEL");
assertEquals(2, rules.size()); assertEquals(2, rules.size());
assert confirmEntries(rules); assert confirmEntries(rules);
assertSame("EXPRESSION", rules.get(0).getActions().get(0).getType()); assertSame("EXPRESSION", rules.get(0).getActions().get(0).getType());
@ -54,7 +54,7 @@ public class TestRulesFactory {
public void testCreateRulesFromSpelYaml(){ public void testCreateRulesFromSpelYaml(){
try { try {
String testYamlFile = "src/test/resources/test_spel_rules.yml"; String testYamlFile = "src/test/resources/test_spel_rules.yml";
List<Rule> rules = RulesFactory.createRules(testYamlFile,"YAML", "SPEL"); List<Rule> rules = RulesFactory.createRulesFromFile(testYamlFile,"YAML", "SPEL");
assertEquals(2, rules.size()); assertEquals(2, rules.size());
assertSame("EXPRESSION", rules.get(0).getActions().get(0).getType()); assertSame("EXPRESSION", rules.get(0).getActions().get(0).getType());
}catch (Exception ex){ }catch (Exception ex){
@ -66,7 +66,7 @@ public class TestRulesFactory {
public void testCreateRulesFromNiFiJson(){ public void testCreateRulesFromNiFiJson(){
try { try {
String testJsonFile = "src/test/resources/test_nifi_rules.json"; String testJsonFile = "src/test/resources/test_nifi_rules.json";
List<Rule> rules = RulesFactory.createRules(testJsonFile,"JSON", "NIFI"); List<Rule> rules = RulesFactory.createRulesFromFile(testJsonFile,"JSON", "NIFI");
assertEquals(2, rules.size()); assertEquals(2, rules.size());
assert confirmEntries(rules); assert confirmEntries(rules);
}catch (Exception ex){ }catch (Exception ex){
@ -78,7 +78,7 @@ public class TestRulesFactory {
public void testCreateRulesFromMvelJson(){ public void testCreateRulesFromMvelJson(){
try { try {
String testJsonFile = "src/test/resources/test_mvel_rules.json"; String testJsonFile = "src/test/resources/test_mvel_rules.json";
List<Rule> rules = RulesFactory.createRules(testJsonFile,"JSON", "MVEL"); List<Rule> rules = RulesFactory.createRulesFromFile(testJsonFile,"JSON", "MVEL");
assertEquals(2, rules.size()); assertEquals(2, rules.size());
assertSame("EXPRESSION", rules.get(0).getActions().get(0).getType()); assertSame("EXPRESSION", rules.get(0).getActions().get(0).getType());
assert confirmEntries(rules); assert confirmEntries(rules);
@ -91,7 +91,59 @@ public class TestRulesFactory {
public void testCreateRulesFromSpelJson(){ public void testCreateRulesFromSpelJson(){
try { try {
String testJsonFile = "src/test/resources/test_spel_rules.json"; String testJsonFile = "src/test/resources/test_spel_rules.json";
List<Rule> rules = RulesFactory.createRules(testJsonFile,"JSON", "SPEL"); List<Rule> rules = RulesFactory.createRulesFromFile(testJsonFile,"JSON", "SPEL");
assertEquals(2, rules.size());
assertSame("EXPRESSION", rules.get(0).getActions().get(0).getType());
}catch (Exception ex){
fail("Unexpected exception occurred: "+ex.getMessage());
}
}
@Test
public void testCreateRulesFromStringSpelJson(){
try {
String testJson = "[\n" +
" {\n" +
" \"name\": \"Queue Size\",\n" +
" \"description\": \"Queue size check greater than 50\",\n" +
" \"priority\": 1,\n" +
" \"condition\": \"#predictedQueuedCount > 50\",\n" +
" \"actions\": [\"#predictedQueuedCount + 'is large'\"]\n" +
" },\n" +
" {\n" +
" \"name\": \"Time To Back Pressure\",\n" +
" \"description\": \"Back pressure time less than 5 minutes\",\n" +
" \"priority\": 2,\n" +
" \"condition\": \"#predictedTimeToBytesBackpressureMillis < 300000 && #predictedTimeToBytesBackpressureMillis >= 0\",\n" +
" \"actions\": [\"'System is approaching backpressure! Predicted time left: ' + #predictedTimeToBytesBackpressureMillis\"]\n" +
" }\n" +
"]";
List<Rule> rules = RulesFactory.createRulesFromString(testJson,"JSON", "SPEL");
assertEquals(2, rules.size());
assertSame("EXPRESSION", rules.get(0).getActions().get(0).getType());
}catch (Exception ex){
fail("Unexpected exception occurred: "+ex.getMessage());
}
}
@Test
public void testCreateRulesFromStringSpelYaml(){
try {
String testYaml = "---\n" +
"name: \"Queue Size\"\n" +
"description: \"Queue size check greater than 50\"\n" +
"priority: 1\n" +
"condition: \"#predictedQueuedCount > 50\"\n" +
"actions:\n" +
" - \"System.out.println(\\\"Queue Size Over 50 is detected!\\\")\"\n" +
"---\n" +
"name: \"Time To Back Pressure\"\n" +
"description: \"Back pressure time less than 5 minutes\"\n" +
"priority: 2\n" +
"condition: \"#predictedTimeToBytesBackpressureMillis < 300000 && #predictedTimeToBytesBackpressureMillis >= 0\"\n" +
"actions:\n" +
" - \"System.out.println(\\\"Back Pressure prediction less than 5 minutes!\\\")\"";
List<Rule> rules = RulesFactory.createRulesFromString(testYaml,"YAML", "SPEL");
assertEquals(2, rules.size()); assertEquals(2, rules.size());
assertSame("EXPRESSION", rules.get(0).getActions().get(0).getType()); assertSame("EXPRESSION", rules.get(0).getActions().get(0).getType());
}catch (Exception ex){ }catch (Exception ex){
@ -102,7 +154,7 @@ public class TestRulesFactory {
@Test @Test
public void testFakeTypeNotSupported(){ public void testFakeTypeNotSupported(){
try { try {
RulesFactory.createRules("FAKEFILE", "FAKE", "NIFI"); RulesFactory.createRulesFromFile("FAKEFILE", "FAKE", "NIFI");
}catch (Exception ex){ }catch (Exception ex){
return; return;
} }
@ -112,7 +164,7 @@ public class TestRulesFactory {
@Test @Test
public void testFakeFormatNotSupported(){ public void testFakeFormatNotSupported(){
try { try {
RulesFactory.createRules("FAKEFILE", "JSON", "FAKE"); RulesFactory.createRulesFromFile("FAKEFILE", "JSON", "FAKE");
}catch (Exception ex){ }catch (Exception ex){
return; return;
} }

View File

@ -142,6 +142,75 @@ public class TestEasyRulesEngineService {
assertEquals(actions.size(), 2); assertEquals(actions.size(), 2);
} }
@Test
public void testJsonSpelRulesAsString() throws InitializationException, IOException {
final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
final RulesEngineService service = new MockEasyRulesEngineService();
runner.addControllerService("easy-rules-engine-service-test",service);
String testRules = "[\n" +
" {\n" +
" \"name\": \"Queue Size\",\n" +
" \"description\": \"Queue size check greater than 50\",\n" +
" \"priority\": 1,\n" +
" \"condition\": \"#predictedQueuedCount > 50\",\n" +
" \"actions\": [\"#predictedQueuedCount + 'is large'\"]\n" +
" },\n" +
" {\n" +
" \"name\": \"Time To Back Pressure\",\n" +
" \"description\": \"Back pressure time less than 5 minutes\",\n" +
" \"priority\": 2,\n" +
" \"condition\": \"#predictedTimeToBytesBackpressureMillis < 300000 && #predictedTimeToBytesBackpressureMillis >= 0\",\n" +
" \"actions\": [\"'System is approaching backpressure! Predicted time left: ' + #predictedTimeToBytesBackpressureMillis\"]\n" +
" }\n" +
"]";
runner.setProperty(service, EasyRulesEngineService.RULES_BODY, testRules);
runner.setProperty(service,EasyRulesEngineService.RULES_FILE_TYPE, "JSON");
runner.setProperty(service,EasyRulesEngineService.RULES_FILE_FORMAT, "SPEL");
runner.enableControllerService(service);
runner.assertValid(service);
Map<String, Object> facts = new HashMap<>();
facts.put("predictedQueuedCount",60);
facts.put("predictedTimeToBytesBackpressureMillis",299999);
List<Action> actions = service.fireRules(facts);
assertNotNull(actions);
assertEquals(actions.size(), 2);
}
@Test
public void testYamlMvelRulesAsString() throws InitializationException, IOException {
final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);
final RulesEngineService service = new MockEasyRulesEngineService();
runner.addControllerService("easy-rules-engine-service-test",service);
String testYaml = "---\n" +
"name: \"Queue Size\"\n" +
"description: \"Queue size check greater than 50\"\n" +
"priority: 1\n" +
"condition: \"predictedQueuedCount > 50\"\n" +
"actions:\n" +
" - \"System.out.println(\\\"Queue Size Over 50 is detected!\\\")\"\n" +
"---\n" +
"name: \"Time To Back Pressure\"\n" +
"description: \"Back pressure time less than 5 minutes\"\n" +
"priority: 2\n" +
"condition: \"predictedTimeToBytesBackpressureMillis < 300000 && predictedTimeToBytesBackpressureMillis >= 0\"\n" +
"actions:\n" +
" - \"System.out.println(\\\"Back Pressure prediction less than 5 minutes!\\\")\"";
runner.setProperty(service, EasyRulesEngineService.RULES_BODY, testYaml);
runner.setProperty(service,EasyRulesEngineService.RULES_FILE_TYPE, "YAML");
runner.setProperty(service,EasyRulesEngineService.RULES_FILE_FORMAT, "MVEL");
runner.enableControllerService(service);
runner.assertValid(service);
Map<String, Object> facts = new HashMap<>();
facts.put("predictedQueuedCount",60);
facts.put("predictedTimeToBytesBackpressureMillis",299999);
List<Action> actions = service.fireRules(facts);
assertNotNull(actions);
assertEquals(actions.size(), 2);
}
@Test @Test
public void testIgnoreConditionErrorsFalseNIFI() throws InitializationException, IOException { public void testIgnoreConditionErrorsFalseNIFI() throws InitializationException, IOException {
final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class); final TestRunner runner = TestRunners.newTestRunner(TestProcessor.class);