This is working correctly. Both rules meet the conditions to fire, so both rules do fire.
If you don't want the AB rule to fire when the C condition is passed, you need to write it so that it explicitly doesn't trigger.
Here's an example:
rule "ABC"
when
A()
B()
C()
then
System.out.println("ABC");
end
rule "AB not C"
when
A()
B()
not( C() )
then
System.out.println("AB not C");
end
In this example, if you pass objects A
, B
, and C
into the rules, only the first rule will fire because the second rule is mutually exclusive: it will only trigger when C
is not present. Similarly, if you only pass A
and B
in, but not C
, then only the second rule will fire because the first rule requires C
and the requirement is not met.
Without the not( C() )
condition, you'd have what you have in your example: the rule will fire regardless of the presence (or abscence) of the C object in memory because it is entirely irrelevant. You ask if you can make C optional -- as you have it, C is optional. If it is present or not does not matter.
Note that exactly how you negate condition "C" depends on what it actually is. If your fact was instead like this: MyObj( a == 1, b == 2, c >= 3)
, then you'd negate C by having the AB rule key on: MyObj( a == 1, b == 2, c < 3)
. You simply need to invert the "C" condition check, whatever it is.
For completeness sake, it's worth mentioning that you can modify the items in working memory in order to keep the second rule from firing after the first does. If these two rules live in a vacuum, this might bee the solution for you; if they're a part of a larger rule set there are likely other rules depending on these same facts which might cause unintended consequences.
Firstly, you can insert a "flag" into working memory and key off of its presence (or lack thereof) in the rule you don't want to trigger. So if you don't want AB to trigger if ABC was triggered you can insert a flag on the right hand side of the ABC rule:
declare Flag
name: String
end
rule "ABC with flag"
when
A()
B()
C()
then
Flag f = new Flag();
f.setName("ABC");
insert( f )
end
rule "AB but not if ABC"
when
A()
B()
not( Flag(name = "ABC" ))
then
//...
end
Here, rule ABC inserts a flag when it fires; rule AB checks for the presence of the flag before firing.
Alternatively you can retract
facts from working memory, so that rules which require that data no longer trigger. This potentially has wide-reaching consequences (data is actually removed from working memory so when Drools reevaluates all rules for being valid you might trigger unexpected ones) so it's generally not recommended that you do this.