Как использовать переменные в простых правилах? - PullRequest
2 голосов
/ 06 мая 2020

Я использую JSON descriptor для загрузки правил, используя easy-rules , и я хочу использовать переменные в простых правилах 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\":\"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\\\"]}\"]);"
    ]
  }
]

Возможны ли следующие 2 вещи здесь

-> Использовать правило name, description внутри действий?

...
[
  {
    "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\\\"]}\"]);"
    ]
  }
]
...

-> Использовать переменную в действиях?

...
"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\\\"]}\"]);"
    ]
...

Обновить Здесь я инициализирую 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 +
                '}';
    }
}

Ответы [ 2 ]

1 голос
/ 17 мая 2020

Вы в основном пытаетесь получить доступ к информации правила внутри условия / действия, или, другими словами, сделать условие / действие осведомленным о правиле. Это можно сделать с помощью прослушивателя правил, который помещает правило как факт перед выполнением правила и удаляет его впоследствии. Вот быстрый пример:

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
}

И вот как его использовать: Учитывая следующий файл описания правила 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);"
    ]
  }
]

Следующий пример печатает 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);
    }
}

Это означает, что действие смогло получить доступ к имени правила, частью которого оно было. Пример показывает, как сделать действие осведомленным о своем правиле, но оно также должно работать для условий.

1 голос
/ 15 мая 2020

Подводя итог, нет и да!

Чтобы понять, как, вы должны понимать, что пока переменная присутствует как Fact или каким-то образом присутствует в контексте MVEL, она может быть решенным.

Вот подробные ответы -

Использовать правило name, description внутри действий?

Нет. Вы не можете использовать Rule name и description внутри Action. Чтобы использовать внешние переменные внутри правил, вам нужно добавить их как факты. Если вам нужна эта возможность, используйте drools, что намного больше богатый набор функций и тяжелый фреймворк.

Использовать переменную в действиях?

Это вы можете сделать, но не так, как вы. def имеет особое значение внутри MVEL. Итак, чтобы использовать переменные, вы можете сделать одно из этих действий -

  1. Определить переменную как отдельный элемент действия:

    "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. Добавить встроенные переменные :

    "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\\\"]}\"]);"
    ]
    

    Обратите внимание, что вам не нужны дополнительные quotes при использовании их внутри действия.

Надеюсь, это поможет!

...