16.12.3. Rule unit identity conflicts
In rule unit execution scenarios with guarded rule units, a rule can guard multiple rule units and at the same time a rule unit can be guarded and then activated by multiple rules. For these two-way guarding scenarios, rule units must have a clearly defined identity to avoid identity conflicts.
By default, the identity of a rule unit is the rule unit class name and is treated as a singleton class by the RuleUnitExecutor
. This identification behavior is encoded in the getUnitIdentity()
default method of the RuleUnit
interface:
Default identity method in the RuleUnit
interface
default Identity getUnitIdentity() { return new Identity( getClass() ); }
In some cases, you may need to override this default identification behavior to avoid conflicting identities between rule units.
For example, the following RuleUnit
class contains a DataSource
definition that accepts any kind of object:
Example Unit0
rule unit class
public class Unit0 implements RuleUnit { private DataSource<Object> input; public DataSource<Object> getInput() { return input; } }
This rule unit contains the following DRL rule that guards another rule unit based on two conditions (in OOPath notation):
Example GuardAgeCheck
DRL rule in the rule unit
package org.mypackage.myunit unit Unit0 rule GuardAgeCheck when $i: /input#Integer $s: /input#String then drools.guard( new AgeCheckUnit($i) ); drools.guard( new AgeCheckUnit($s.length()) ); end
The guarded AgeCheckUnit
rule unit verifies the age of a set of persons
. The AgeCheckUnit
contains a DataSource
definition of the persons
to check, a minAge
variable that it verifies against, and a List
for gathering the results:
Example AgeCheckUnit
rule unit
public class AgeCheckUnit implements RuleUnit { private final int minAge; private DataSource<Person> persons; private List<String> results; public AgeCheckUnit( int minAge ) { this.minAge = minAge; } public DataSource<Person> getPersons() { return persons; } public int getMinAge() { return minAge; } public List<String> getResults() { return results; } }
The AgeCheckUnit
rule unit contains the following DRL rule that performs the verification of the persons
in the data source:
Example CheckAge
DRL rule in the rule unit
package org.mypackage.myunit unit AgeCheckUnit rule CheckAge when $p : /persons{ age > minAge } then results.add($p.getName() + ">" + minAge); end
This example creates a RuleUnitExecutor
class, binds the class to the KIE base that contains these two rule units, and creates the two DataSource
definitions for the same rule units:
Example executor and data source definitions
RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase ); DataSource<Object> input = executor.newDataSource( "input" ); DataSource<Person> persons = executor.newDataSource( "persons", new Person( "John", 42 ), new Person( "Sally", 4 ) ); List<String> results = new ArrayList<>(); executor.bindVariable( "results", results );
You can now insert some objects into the input data source and execute the Unit0
rule unit:
Example rule unit execution with inserted objects
ds.insert("test"); ds.insert(3); ds.insert(4); executor.run(Unit0.class);
Example results list from the execution
[Sally>3, John>3]
In this example, the rule unit named AgeCheckUnit
is considered a singleton class and then executed only once, with the minAge
variable set to 3
. Both the String "test"
and the Integer 4
inserted into the input data source can also trigger a second execution with the minAge
variable set to 4
. However, the second execution does not occur because another rule unit with the same identity has already been evaluated.
To resolve this rule unit identity conflict, override the getUnitIdentity()
method in the AgeCheckUnit
class to include also the minAge
variable in the rule unit identity:
Modified AgeCheckUnit
rule unit to override the getUnitIdentity()
method
public class AgeCheckUnit implements RuleUnit { ... @Override public Identity getUnitIdentity() { return new Identity(getClass(), minAge); } }
With this override in place, the previous example rule unit execution produces the following output:
Example results list from executing the modified rule unit
[John>4, Sally>3, John>3]
The rule units with minAge
set to 3
and 4
are now considered two different rule units and both are executed.