87.3. State example decisions (forward chaining and conflict resolution)
The State example decision set demonstrates how the decision engine uses forward chaining and any changes to facts in the working memory to resolve execution conflicts for rules in a sequence. The example focuses on resolving conflicts through salience values or through agenda groups that you can define in rules.
The following is an overview of the State example:
-
Name:
state
-
Main classes:
org.drools.examples.state.StateExampleUsingSalience
,org.drools.examples.state.StateExampleUsingAgendaGroup
(insrc/main/java
) -
Module:
drools-examples
- Type: Java application
-
Rule files:
org.drools.examples.state.*.drl
(insrc/main/resources
) - Objective: Demonstrates forward chaining and conflict resolution through rule salience and agenda groups
A forward-chaining rule system is a data-driven system that starts with a fact in the working memory of the decision engine and reacts to changes to that fact. When objects are inserted into working memory, any rule conditions that become true as a result of the change are scheduled for execution by the agenda.
In contrast, a backward-chaining rule system is a goal-driven system that starts with a conclusion that the decision engine attempts to satisfy, often using recursion. If the system cannot reach the conclusion or goal, it searches for subgoals, which are conclusions that complete part of the current goal. The system continues this process until either the initial conclusion is satisfied or all subgoals are satisfied.
The decision engine in Red Hat Decision Manager uses both forward and backward chaining to evaluate rules.
The following diagram illustrates how the decision engine evaluates rules using forward chaining overall with a backward-chaining segment in the logic flow:
図87.4 Rule evaluation logic using forward and backward chaining
In the State example, each State
class has fields for its name and its current state (see the class org.drools.examples.state.State
). The following states are the two possible states for each object:
-
NOTRUN
-
FINISHED
State class
public class State { public static final int NOTRUN = 0; public static final int FINISHED = 1; private final PropertyChangeSupport changes = new PropertyChangeSupport( this ); private String name; private int state; ... setters and getters go here... }
The State example contains two versions of the same example to resolve rule execution conflicts:
-
A
StateExampleUsingSalience
version that resolves conflicts by using rule salience -
A
StateExampleUsingAgendaGroups
version that resolves conflicts by using rule agenda groups
Both versions of the state example involve four State
objects: A
, B
, C
, and D
. Initially, their states are set to NOTRUN
, which is the default value for the constructor that the example uses.
State example using salience
The StateExampleUsingSalience
version of the State example uses salience values in rules to resolve rule execution conflicts. Rules with a higher salience value are given higher priority when ordered in the activation queue.
The example inserts each State
instance into the KIE session and then calls fireAllRules()
.
Salience State example execution
final State a = new State( "A" ); final State b = new State( "B" ); final State c = new State( "C" ); final State d = new State( "D" ); ksession.insert( a ); ksession.insert( b ); ksession.insert( c ); ksession.insert( d ); ksession.fireAllRules(); // Dispose KIE session if stateful (not required if stateless). ksession.dispose();
To execute the example, run the org.drools.examples.state.StateExampleUsingSalience
class as a Java application in your IDE.
After the execution, the following output appears in the IDE console window:
Salience State example output in the IDE console
A finished B finished C finished D finished
Four rules are present.
First, the "Bootstrap"
rule fires, setting A
to state FINISHED
, which then causes B
to change its state to FINISHED
. Objects C
and D
are both dependent on B
, causing a conflict that is resolved by the salience values.
To better understand the execution flow of this example, you can load the audit log file from target/state.log
into your IDE debug view or Audit View, if available (for example, in Window → Show View in some IDEs).
In this example, the Audit View shows that the assertion of the object A
in the state NOTRUN
activates the "Bootstrap"
rule, while the assertions of the other objects have no immediate effect.
図87.5 Salience State example Audit View
Rule "Bootstrap" in salience State example
rule "Bootstrap" when a : State(name == "A", state == State.NOTRUN ) then System.out.println(a.getName() + " finished" ); a.setState( State.FINISHED ); end
The execution of the "Bootstrap"
rule changes the state of A
to FINISHED
, which activates rule "A to B"
.
Rule "A to B" in salience State example
rule "A to B" when State(name == "A", state == State.FINISHED ) b : State(name == "B", state == State.NOTRUN ) then System.out.println(b.getName() + " finished" ); b.setState( State.FINISHED ); end
The execution of rule "A to B"
changes the state of B
to FINISHED
, which activates both rules "B to C"
and "B to D"
, placing their activations onto the decision engine agenda.
Rules "B to C" and "B to D" in salience State example
rule "B to C" salience 10 when State(name == "B", state == State.FINISHED ) c : State(name == "C", state == State.NOTRUN ) then System.out.println(c.getName() + " finished" ); c.setState( State.FINISHED ); end rule "B to D" when State(name == "B", state == State.FINISHED ) d : State(name == "D", state == State.NOTRUN ) then System.out.println(d.getName() + " finished" ); d.setState( State.FINISHED ); end
From this point on, both rules may fire and, therefore, the rules are in conflict. The conflict resolution strategy enables the decision engine agenda to decide which rule to fire. Rule "B to C"
has the higher salience value (10
versus the default salience value of 0
), so it fires first, modifying object C
to state FINISHED
.
The Audit View in your IDE shows the modification of the State
object in the rule "A to B"
, which results in two activations being in conflict.
You can also use the Agenda View in your IDE to investigate the state of the decision engine agenda. In this example, the Agenda View shows the breakpoint in the rule "A to B"
and the state of the agenda with the two conflicting rules. Rule "B to D"
fires last, modifying object D
to state FINISHED
.
図87.6 Salience State example Agenda View
State example using agenda groups
The StateExampleUsingAgendaGroups
version of the State example uses agenda groups in rules to resolve rule execution conflicts. Agenda groups enable you to partition the decision engine agenda to provide more execution control over groups of rules. By default, all rules are in the agenda group MAIN
. You can use the agenda-group
attribute to specify a different agenda group for the rule.
Initially, a working memory has its focus on the agenda group MAIN
. Rules in an agenda group only fire when the group receives the focus. You can set the focus either by using the method setFocus()
or the rule attribute auto-focus
. The auto-focus
attribute enables the rule to be given a focus automatically for its agenda group when the rule is matched and activated.
In this example, the auto-focus
attribute enables rule "B to C"
to fire before "B to D"
.
Rule "B to C" in agenda group State example
rule "B to C" agenda-group "B to C" auto-focus true when State(name == "B", state == State.FINISHED ) c : State(name == "C", state == State.NOTRUN ) then System.out.println(c.getName() + " finished" ); c.setState( State.FINISHED ); kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "B to D" ).setFocus(); end
The rule "B to C"
calls setFocus()
on the agenda group "B to D"
, enabling its active rules to fire, which then enables the rule "B to D"
to fire.
Rule "B to D" in agenda group State example
rule "B to D" agenda-group "B to D" when State(name == "B", state == State.FINISHED ) d : State(name == "D", state == State.NOTRUN ) then System.out.println(d.getName() + " finished" ); d.setState( State.FINISHED ); end
To execute the example, run the org.drools.examples.state.StateExampleUsingAgendaGroups
class as a Java application in your IDE.
After the execution, the following output appears in the IDE console window (same as the salience version of the State example):
Agenda group State example output in the IDE console
A finished B finished C finished D finished
Dynamic facts in the State example
Another notable concept in this State example is the use of dynamic facts, based on objects that implement a PropertyChangeListener
object. In order for the decision engine to see and react to changes of fact properties, the application must notify the decision engine that changes occurred. You can configure this communication explicitly in the rules by using the modify
statement, or implicitly by specifying that the facts implement the PropertyChangeSupport
interface as defined by the JavaBeans specification.
This example demonstrates how to use the PropertyChangeSupport
interface to avoid the need for explicit modify
statements in the rules. To make use of this interface, ensure that your facts implement PropertyChangeSupport
in the same way that the class org.drools.example.State
implements it, and then use the following code in the DRL rule file to configure the decision engine to listen for property changes on those facts:
Declaring a dynamic fact
declare type State @propertyChangeSupport end
When you use PropertyChangeListener
objects, each setter must implement additional code for the notification. For example, the following setter for state
is in the class org.drools.examples
:
Setter example with PropertyChangeSupport
public void setState(final int newState) { int oldState = this.state; this.state = newState; this.changes.firePropertyChange( "state", oldState, newState ); }