-
Notifications
You must be signed in to change notification settings - Fork 124
Rules
Rules are the basic building blocks of RuleBook. They are the individual conditions and actions that evaluate and act on facts, respectively. Rules contain facts and optionally a Result. And all Rules implement the com.deliveredtechnologies.rulebook.model.Rule interface.
RuleBook comes packaged with a single implementation of the Rule interface, GoldenRule. However, you are welcome to create your own implementation of the Rule interface and use that instead. But you shouldn't need to. GoldenRule should have all you need. The rest of the page will discuss Rules in the context of the functionality implemented in GoldenRule.
A Rule, by itself can accept facts, evaluate a condition based on those facts, execute one or more actions if that condition evaluates to true and (optionally) maintain a Result. The real magic comes when Rules are chained together in a RuleBook. However, this page limits the discussion to how a Rule itself works. If you want to know more about how Rules are executed in the context of a RuleBook, see the RuleBooks page in this Wiki.
A Rule can have a single condition, which is a Predicate functional interface. When that condition evaluates to true, each of the actions specified for the Rule are executed in the order in which they were specified. If no condition exists for a Rule, the condition is assumed to be true.
Rules are invoked using the invoke() method, which returns a boolean result. The invoke() method returns true if the actions of the Rule execute without error. Otherwise, the invoke() method will return false.
Since a Rule's condition is supplied by a Predicate functional interface, a common way to define the implementation of that interface is through Java's Lambda syntax. The type of the parameter used in the Predicate is NameValueReferableTypeConvertibleMap, which is really just NameValueReferableMap (impl: FactMap) with some type conversion convenience methods attached to it. Of course, as a Predicate, the return type is boolean.
An important thing to note about evaluating conditions is that facts supplied to the condition are filtered by the type of facts evaluated by the Rule. Below is an example that illustrates this point.
Rule<String, Object> rule = new GoldenRule<>(String.class);
rule.addFacts(new Fact("str", "String Value"), new Fact("bool", true));
rule.setCondition(facts -> facts.getValue("bool"));
rule.addAction(facts -> System.out.println(facts.getValue("str")));
rule.invoke(); //returns false; invocation of the condition will fail since "bool" fact is not available
In the above example, the action that prints the value of the "str" fact is not executed. The reason the action is not executed is because the type of the facts used in the Rule is String, but "bool" is type Boolean. And since Boolean does not match the type of facts used by the Rule, it is not available in the Rule's condition.
A Rule's actions are invoked upon the execution of the invoke() method in the order in which they are added to the Rule if and only if the Rule's condition evaluates to true. If any action throws an exception, if the condition throws an exception or if the condition does not evaluate to true then the invoke() method will return false. However, if the condition evaluates to true and if all actions execute successfully, then the invoke() method will return true.
Like a Rule's condition, the facts available to a Rule's action are filtered by the type of facts that are used by the Rule as shown in the following example.
Rule<String, Object> rule = new GoldenRule<>(String.class);
rule.addFacts(new Fact("str", "String Value"), new Fact("bool", true));
rule.addAction(System.out:println); //only the "str" fact is available because it's the only String fact
rule.invoke(); //returns true
Unlike a Rule's condition, actions can accept facts or facts and a result as shown in the example below.
Rule<Boolean, String> rule = new GoldenRule<>(String.class);
rule.addFacts(new Fact("str", "String Value"), new Fact("bool", true));
rule.setCondition(facts -> facts.getOne())
rule.addAction(System.out:println); //only the "bool" fact is available because it's the only Boolean fact
rule.addAction((facts, result) -> result.setResult("Completed rule actions!")); //the Result type is String!
if (rule.invoke()) { //should evaluate to true because all actions should execute
rule.getResult().ifPresent(System.out::println);
}
The above example should print the following.
true
Completed rule actions!