Before we talk about how to manage rule execution order, we have to understand Drools Agenda. When an object is inserted into the knowledge session, Drools tries to match this object with all of the possible rules. If a rule has all of its conditions met, its consequence can be executed. We say that a rule is activated. Drools records this event by placing this rule onto its agenda (it is a collection of activated rules). As you may imagine, many rules can be activated, and also deactivated, depending on what objects are in the rule session. After the fireAllRules method call, Drools picks one rule from the agenda and executes its consequence. It may or may not cause further activations or deactivations. This continues until the Drools Agenda is empty.
The purpose of the agenda is to manage the execution order of rules.
Methods for managing rule execution order
The following are the methods for managing the rule execution order (from the user’s perspective). They can be viewed as alternatives to ruleflow. All of them are defined as rule attributes.
- salience: This is the most basic one. Every rule has a salience value. By default it is set to 0. Rules with higher salience value will fire first. The problem with this approach is that it is hard to maintain. If we want to add new rule with some priority, we may have to shift the priorities of existing rules. It is often hard to figure out why a rule has certain salience, so we have to comment every salience value. It creates an invisible dependency on other rules.
- activation-group: This used to be called xor-group. When two or more rules with the same activation group are on the agenda, Drools will fire just one of them.
- agenda-group: Every rule has an agenda group. By default it is MAIN. However, it can be overridden. This allows us to partition Drools Agenda into multiple groups that can be executed separately.
The figure above shows partitioned Agenda with activated rules. The matched rules are coming from left and going into Agenda. One rule is chosen from the Agenda at a time and then executed/fired.
At runtime, we can programmatically set the active Agenda group (through the getAgenda().getAgendaGroup(String agendaGroup).setFocus() method of KnowledgeRuntime), or declaratively, by setting the rule attribute auto-focus to true. When a rule is activated and has this attribute set to true, the active agenda group is automatically changed to rule’s agenda group. Drools maintains a stack of agenda groups. Whenever the focus is set to a different agenda group, Drools adds this group onto this stack. When there are no rules to fire in the current agenda group, Drools pops from the stack and sets the agenda group to the next one. Agenda groups are similar to ruleflow groups with the exception that ruleflow groups are not stacked.
Note that only one instance of each of these attributes is allowed per rule (for example, a rule can only be in one ruleflow-group ; however, it can also define salience within that group).
As we’ve already said, ruleflow can externalize the execution order from the rule definitions. Rules just define a ruleflow-group attribute, which is similar to agenda-group. It is then used to define the execution order. A simple ruleflow (in the example.rf file) is shown in the following screenshot:
The preceding screenshot shows a ruleflow opened with the Drools Eclipse plugin. On the lefthand side are the components that can be used when building a ruleflow. On the righthand side is the ruleflow itself. It has a Start node which goes to ruleflow group called Group 1. After it finishes execution, an Action is executed, then the flow continues to another ruleflow group called Group 2, and finally it finishes at an End node.
Ruleflow definitions are stored in a file with the .rf extension. This file has an XML format and defines the structure and layout for presentational purposes.
Another useful rule attribute for managing which rules can be activated is lock-on-active. It is a special form of the no-loop attribute. It can be used in combination with ruleflow-group or agenda-group. If it is set to true, and an agenda/ruleflow group becomes active/focused, it discards any further activations for the rule until a different group becomes active. Please note that activations that are already on the agenda will be fired.
A ruleflow consists of various nodes. Each node has a name, type, and other specific attributes. You can see and change these attributes by opening the standard Properties view in Eclipse while editing the ruleflow file. The basic node types are as follows:
They are discussed in the following sections.
It is the initial node. The flow begins here. Each ruleflow needs one start node. This node has no incoming connection—just one outgoing connection.
It is a terminal node. When execution reaches this node, the whole ruleflow is terminated (all of the active nodes are canceled). This node has one incoming connection and no outgoing connections.
Used to execute some arbitrary block of code. It is similar to the rule consequence—it can reference global variables and can specify dialect.
This node will activate a ruleflow-group, as specified by its RuleFlowGroup attribute. It should match the value in ruleflow-group rule attribute.