Search code examples
drools

Single inheritance in drools


We are using drools 7.31 version. We have one big rule which must be reused in other rules. The basic functionality we need is to fire the SUPER rule when both SUPER rule and SUB rule conditions are true. It seems like older version had "extends" keyword using which this was possible. I was looking at this older post which is able to achieve this -

drools rules inheritance

When I tried on my end with 7.31 version, then both SUPER and SUB rules are firing independently. Here is an example of what I am trying to achieve:

rule "super"
    @description("Generic super rule")
    when 
        $person : Person()
        a : PersonInput() from $person.getInput()
        if (a.getPersonId() == 1) break[pvd1]
        else if (a.getPersonId() == 2) break[pvd2]
    then System.out.println("Default then = " + a.getPersonId());
    then[pvd1] System.out.println("Super RULE has person id = " + a.getPersonId());
    then[pvd2] System.out.println("Super RULE has person id = " + a.getPersonId());
end

rule "sub" extends "super"
    @description("Sub rule")
    when
        c : PersonInput(HouseholdId == "99999") from $person.getInput()
    then
        System.out.println("Sub RULE has HouseholdId == 99999 == " + c.getPersonId());
end

The output I am getting is all persons with personId 1/2 of all households first, then then 2nd rule is printing only 99999 household id.

The output that I expect is just to print personId 1/2 of householdId 99999.

Thanks.


Solution

  • Drools 7.31 still supports the 'extends' mechanism. The issue here is that when you extend a base rule, the base rule does fire. (This is kind of obvious; if the base rule isn't valid to fire, then the child rule isn't valid to fire. If the base is valid to fire, then it fires. And when the child rule fires, it also fires the parent rule.)

    The traditional way to work around this is to use three rules. The "base" rule should have no consequences (that is, no right hand side/then clause) so it simply lists out the common conditions. Then the "super" rule's consequences are in a rule that extends the base rules, doesn't have any additional 'when' conditions, and has the then clause as normal. And the "sub" rule also extends "base", includes its additional conditions, and then its own consequences. If you don't want "super" to fire when "sub" does, you make them mutually exclusive.

    Here's an intentionally simplified example:

    rule "Base Rule"
    when
      $person: Person( $input: input != null )
      PersonInput( $id: personId in (1, 2) )
    then
    // intentionally no 'then' clauses
    end
    
    rule "Super" extends "Base Rule"
    when
      // No additional conditions, just use whatever is in Base Rule
    then
      System.out.println("Person has id: " + $id);
    end
    
    rule "Sub" extends "Base Rule"
    when
      PersonInput( householdId == "99999") from $input
    then
      System.out.println("Household ID is 99999; id: " + $id);
    end
    

    Now if we don't want "Super" to fire when "Sub" does, we just make it mutually exclusive from "Sub":

    rule "Super" extends "Base Rule"
    when
      // This is the condition from Sub, inverted:
      PersonInput( householdId != "99999" ) from $input
    then
      System.out.println("Person has id: " + $id);
    end
    

    Basically, when you extend a rule, you're extending both the when and the then clauses. The then clause (consequences) of the parent rule will fire before the consequences of the child rule. Further, if the child is not valid, but the parent is, you will still fire the parent. So if you have (say) 3 child rules and a parent rule, the parent may be fired up to 4 times: once when it by itself is evaluated, and then 3 more times once per child evaluation. Things get particularly odd when you use stateful sessions and update/insert clauses.

    The "no consequence" base rule pattern I've shown evolved out of this reality. Following this pattern, it makes no difference how many times "Base Rule" gets fired because there are no side effects (consequences/then clause).