Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use variables in easy rules?

Tags:

I am using JSON descriptor to load rules using easy-rules and I want to use variables in easy rules actions. For example I have a set of rules where I define rule id, name, description as given below

[
  {
    "id": 1,
    "name": "Task using Oracle DB",
    "description": "Updated comments to update connector",
    "priority": 1,
    "condition": "user.getTaskData().getTargetConnectorType().contains(\"Oracle\") || user.getTaskData().getSourceConnectorType().contains(\"Oracle\")",
    "actions": [
      "user.setRuleDetail([\"impacted_feature\":\"Task using Oracle DB\", \"desc\": \"Updated comments to update connector\", \"impact\":\"low\", \"count\":\"Using \"+user.getTaskDetail().getConnBucketData().get(\"Oracle\")+\" connector type\",\"id\":1, \"extra_detail\":\"{\\\"impacted_connectors\\\":[\\\"Oracle\\\"]}\"]);"
    ]
  }
]

Are the following 2 things possible here

-> Use rule name, description inside actions?

...
[
  {
    "id": 1,
    "name": "Task using Oracle DB",
    "description": "Updated comments to update connector",
    "priority": 1,
    "condition": "user.getTaskData().getTargetConnectorType().contains(\"Oracle\") || user.getTaskData().getSourceConnectorType().contains(\"Oracle\")",
    "actions": [
      "user.setRuleDetail([\"impacted_feature\":\"+name+\", \"desc\": \"+description+\", \"impact\":\"low\", \"count\":\"Using \"+user.getTaskDetail().getConnBucketData().get(\"Oracle\")+\" connector type\",\"id\":1, \"extra_detail\":\"{\\\"impacted_connectors\\\":[\\\"Oracle\\\"]}\"]);"
    ]
  }
]
...

-> Use a variable under actions?

...
"actions": [
        "def name = \"Task using Oracle DB\"",
        "def desc = \"Updated comments to update connector\"",
        "def connector = \"Oracle\"",           
      "user.setRuleDetail([\"impacted_feature\":\"+name+\", \"desc\": \"+desc+\", \"impact\":\"low\", \"count\":\"Using \"+user.getTaskDetail().getConnBucketData().get(\"Oracle\")+\" connector type\",\"id\":1, \"extra_detail\":\"{\\\"impacted_connectors\\\":[\\\"Oracle\\\"]}\"]);"
    ]
...

Update Here I am initializing MVELRuleFactory

def computeRules(UserData userData) {
    try {
        Facts facts = new Facts()
        facts.put("user", userData)

        MVELRuleFactory ruleFactory = new MVELRuleFactory(new JsonRuleDefinitionReader())
        Rules rules = ruleFactory.createRules(new FileReader("conf/rules.json"))

        //create a default rules engine and fire rules on known facts
        RulesEngine rulesEngine = new DefaultRulesEngine()
        rulesEngine.fire(rules, facts)
    } catch(FileNotFoundException fnfe) {
        _errorLogger.error("Error in #computeRules {}", fnfe)
    } catch(Exception e) {
        _errorLogger.error("Error in #computeRules {}", e)
    }
    return userData.getRuleDetail()
}

//UserData POJO

@CompileStatic
class UserData {
    String orgKey
    TaskData taskData
    List<Map> ruleDetail

    UserData(String orgKey, TaskData taskData) {
        this.orgKey = orgKey
        this.taskData = taskData
    }

    String getOrgKey() {
        return orgKey
    }

    void setOrgKey(String orgKey) {
        this.orgKey = orgKey
    }

    TaskData getTaskData() {
        return taskData
    }

    void setTaskData(TaskData taskData) {
        this.taskData = taskData
    }

    List<Map> getRuleDetail() {
        return ruleDetail
    }

    void setRuleDetail(Map ruleData) {
        if (this.ruleDetail == null)
            this.ruleDetail = []
        this.ruleDetail.add(ruleData)
    }

    @Override
    public String toString() {
        return "UserData{" +
                "orgKey='" + orgKey + '\'' +
                ", taskData=" + taskData +
                ", ruleDetail=" + ruleDetail +
                '}';
    }
}
like image 567
Ricky Avatar asked May 06 '20 03:05

Ricky


1 Answers

You are basically trying to access rule information inside the condition/action, or in other words, make the condition/action aware of the rule. You can do that using a rule listener that puts the rule as fact before rule execution and removes it afterwards. Here is a quick example:

public class MyListener implements RuleListener {
    @Override
    public void beforeExecute(Rule rule, Facts facts) {
        facts.put("rule", rule);
    }

    @Override
    public void onSuccess(Rule rule, Facts facts) {
        facts.remove("rule");
    }

    @Override
    public void onFailure(Rule rule, Facts facts, Exception exception) {
        facts.remove("rule");
    }

    // implement other methods if needed
}

And here is how to use it: Given the following rule description file rule-aware-action.json:

[
  {
    "name": "rule aware action",
    "description": "a rule where the action is aware of the rule",
    "condition": "true",
    "actions": [
      "System.out.println(rule.name);"
    ]
  }
]

The following example prints rule aware action:

import java.io.FileReader;

import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.RuleListener;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.mvel.MVELRuleFactory;
import org.jeasy.rules.support.reader.JsonRuleDefinitionReader;

public class RuleAwareActionExample {

    public static void main(String[] args) throws Exception {
        MVELRuleFactory mvelRuleFactory = new MVELRuleFactory(new JsonRuleDefinitionReader());
        Rules rules = mvelRuleFactory.createRules(new FileReader("rule-aware-action.json"));
        DefaultRulesEngine rulesEngine = new DefaultRulesEngine();
        rulesEngine.registerRuleListener(new MyListener());
        Facts facts = new Facts();
        rulesEngine.fire(rules, facts);
    }
}

Which means the action was able to access the name of the rule it was part of. The example shows how to make an action aware of its rule, but it should work for conditions as well.

like image 144
Mahmoud Ben Hassine Avatar answered Sep 30 '22 19:09

Mahmoud Ben Hassine