Lightweight rule engine easy – Introduction to rules

Time:2021-4-21

Lightweight rule engine easy rules–Reference

When we write business code, we often need a lot of if / else, which will greatly reduce the readability of the code. Is there a way to avoid a large number of judgment statements in the code? The answer is to use a rule engine, but traditional rule engines are relatively heavy, such as open source drools, which is not suitable for small demand applications. Recently, I saw a Java rule engine like a fool on GitHubEasy-RulesHere, I will introduce how to use this rule engine in combination with my demo, hoping to help you.

Characteristics of easy rules
  • Lightweight class library and easy to use
  • POJO based programming model of development and annotation
  • Mvel expression based programming model (for very simple rules, generally not recommended)
  • Support to create combination rules according to simple rules
  • Convenient and applicable Abstract Business Model Rules for Java

It mainly includes several main classes or interfaces: rule, ruleengine, rulelistener, facts, and several main [email protected] Action,@Condition ,@Fact ,@Priority ,@Rule

Example 1: programming model based on POJO development and annotation: judge the number divided by 3 or 8 in 1-50
  • First, Maven introduces easy rules
      <dependency>
            <groupId>org.jeasy</groupId>
            <artifactId>easy-rules-core</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.jeasy</groupId>
            <artifactId>easy-rules-mvel</artifactId>
            <version>3.3.0</version>
        </dependency>
  • Write rules POJO:

Rule 1

@ Rule ( name  = " Divisible by 3 ",  description  = " If number is divided by 3, print: number is three ")
public class ThreeRule {
    /**
     *  Condition : Condition judgment comment: if return is true, execute action
     *
     * @param number
     * @return
     */
    @Condition
    public boolean isThree(@Fact("number") int number) {
        return number % 3 == 0;
    }

    /**
     *Action execution method annotation
     *
     * @param number
     */
    @Action
    public void threeAction(@Fact("number") int number) {
        System.out.println(number + " is three");
    }

    /**
     *  Priority : Priority note: the lower the return value, the higher the priority
     *
     * @return
     */
    @Priority
    public int getPriority() {
        return 1;
    }
}

Rule 2

@ Rule ( name  = " Divisible by 8 ")
public class EightRule {

    /**
     *  condition
     *
     * @param number
     * @return
     */
    @Condition
    public boolean isEight(@Fact("number") int number) {
        return number % 8 == 0;
    }

    /**
     *Actions that meet the conditions
     *
     * @param number
     */
    @Action
    public void eightAction(@Fact("number") int number) {
        System.out.println(number + " is eight");
    }

    /**
     *  condition判断的优先级
     *
     * @return
     */
    @Priority
    public int getPriority() {
        return 2;
    }
}

Rule 3 (combination rule – simultaneous execution)

@Rule (name = divisible by 3 and 8 at the same time ", description = this is a combination rule)
public class ThreeEightRuleUnitGroup extends UnitRuleGroup {

    public ThreeEightRuleUnitGroup(Object... rules) {
        for (Object rule : rules) {
            addRule(rule);
        }
    }

    @Override
    public int getPriority() {
        return 0;
    }

}

Rule 4

@Rule (name =, neither divisible by 3 nor divisible by 8 ", description =, print number yourself)
public class OtherRule {  
    @Condition
    public boolean isOther(@Fact("number") int number){
        return number % 3 != 0 || number % 8 != 0;
    }

    @Action
    public void printSelf(@Fact("number") int number){
        System.out.print(number);
    }

    @Priority
    public int getPriority(){
        return 3;
    }
}
  • Enforcement rules
public class ThreeEightRuleLauncher {

    public static void main(String[] args) {
        /**
         *  Create rule execution engine
         *Note: skiponfirstapplied rule means that as long as the first rule is matched, the following rule matching will be skipped
         */
        RulesEngineParameters parameters = new 
        RulesEngineParameters().skipOnFirstAppliedRule(true);
        RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
        //Create rules
        Rules rules = new Rules();
        rules.register(new EightRule());
        rules.register(new ThreeRule());
        rules.register(new ThreeEightRuleUnitGroup(new EightRule(), new ThreeRule()));
        rules.register(new OtherRule());
        Facts facts = new Facts();
        for (int i=1 ; i<=50 ; i++){
            // The rule factor, the corresponding name, should be the same as that in the rule @ Fact consistent
            facts.put("number", i);
            //Enforcement rules
            rulesEngine.fire(rules, facts);
            System.out.println();
        }
    }
}
Example 2: programming model based on mvel expression

This example demonstrates how to use mvel expression to define rules. Mvel is provided by easy rules mvel module. This module contains an API for defining rules using mvel. We will use these APIs here, and the goal is to implement a simple store app with the following requirements: children are not allowed to buy alcohol, and the minimum legal age for adults is 18. Store customers are defined by the person class

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String name;

    private boolean adult;

    private int age;
    //Getter, setter omitted


    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

We define two rules:

  • Rule 1: you can update the person instance, judge whether the age is greater than 18, and set the adult flag.
  • Rule 2: judge whether the person is an adult, and refuse children (i.e. non adults) to buy alcohol.

Obviously, the priority of rule 1 is higher than that of rule 2. We can set the priority of rule 1 to 1 and the priority of rule 2 to 2, so that the rule engine can execute the rules in the order of priority when executing the rules.

Definition of rule 1

 Rule ageRule = new MVELRule()
                .name("age rule")
                .description("Check if person's age is > 18 and marks the person as adult")
                .priority(1)
                .when("person.age > 18")
                .then("person.setAdult(true);");

Definition of rule 2Let’s put it in alcohol- rule.yml In the file

name: "alcohol rule"  
description: "children are not allowed to buy alcohol"  
priority: 2  
condition: "person.isAdult() == false"  
actions:  
  - "System.out.println(\"Shop: Sorry, you are not allowed to buy alcohol\");"
  • Enforcement rules
public class ShopLauncher {
    public static void main(String[] args) throws Exception {
        //Create a person instance (fact)
        Person tom = new Person("Tom", 19);
        Facts facts = new Facts();
        facts.put("person", tom);

        //Create rule 1
        Rule ageRule = new MVELRule()
                .name("age rule")
                .description("Check if person's age is > 18 and marks the person as adult")
                .priority(1)
                .when("person.age > 18")
                .then("person.setAdult(true);");
        //Create rule 2
        Rule alcoholRule = new MVELRuleFactory(new YamlRuleDefinitionReader()).
                createRule(new FileReader(ResourceUtils.getFile("classpath:alcohol-rule.yml")));

        Rules rules = new Rules();
        rules.register(ageRule);
        rules.register(alcoholRule);

        //Create a rule execution engine and execute rules
        RulesEngine rulesEngine = new DefaultRulesEngine();
        System.out.println("Tom: Hi! can I have some Vodka please?");
        rulesEngine.fire(rules, facts);
        System.out.println(JSON.toJSONString(tom));
    }
}
  • The results are as follows:Lightweight rule engine easy - Introduction to rulesThis article mainly introduces easy – Use of rules
    For an in-depth understanding of the principle, you can check the GitHub source code:https://github.com/j-easy/easy-rules