How to use variables in easy rules?
Asked Answered
H

2

6

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 +
                '}';
    }
}
Halley answered 6/5, 2020 at 3:24 Comment(7)
what java & groovy tags are doing here?Beaded
@Beaded easy rules is a Java rules engine the code inside actions is written in groovyHalley
as i know github.com/j-easy/easy-rules does not contain groovy implementation for actions.Beaded
@Beaded Sorry my bad the actions use java code using the expression language support, my project is in groovy which is using a mix of both java and groovy.Halley
please edit your question and present at least part of the code - how you are initializing SpELRuleFactoryBeaded
@Beaded I updated my question with code where I initialize MVELRuleFactory classHalley
@Halley I added an answer with a complete example. Hope it helps. Let me know if you need further support.Discord
D
3

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.

Discord answered 17/5, 2020 at 11:16 Comment(0)
I
1

Summarising, no and yes!

To get to how, you have to understand that as long as a variable is present as a Fact or somehow it is present in MVEL context, it can be resolved.

Here's detailed answers-

Use rule name, description inside actions?

No. You can't use Rule's name and description inside an Action. To use external variables inside rules, you'll have to add them as facts. If you want that ability, use drools which is much more feature rich and heavy framework.

Use a variable under actions?

This you can do, however not the way you have. def has a special meaning inside MVEL. So to use variables, you can do either of these things-

  1. Define variable as separate action item:

    "actions": [
       "name=\"....\"",
       "description=\"....\"",
       "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\\\"]}\"]);"
    ]
    
  2. Add inline variables:

    "actions": [
       "name=\"....\";description=\"....\";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\\\"]}\"]);"
    ]
    

    Note how you don't need additional quotes while using them inside action.

Hope this helps!

Inviolable answered 15/5, 2020 at 20:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.