Assuming that your class definition looks like this:
class PurchaseRequest {
private List<Purchase> purchases;
public List<Purchase> getPurchases() { return this.purchases; }
}
You should be pulling references out of the holder instead of constantly interacting with things via the getters. In other projects this helps with keep data consistent especially with shared resources. Recall that if you have a getter whose name matches the format getXyz
, you can refer to it simply as xyz
and drools will automagically map it to the getter function. This allows us to get the purchases via PurchaseRequest( $purchases: purchases )
since purchases
will be mapped to getPurchases()
. (Note that if purchases happened to be a public variable, it would have mapped to that first; but since it's private it falls back on the public getter that follows bean naming conventions.)
Second you use an accumulate
in a very simple scenario where a collect
would probably be more appropriate. Generally you'd use accumulate
for more complicated "get things that look like this" sort of situations; but for simple matching, a collect works just as well.
The third rule needs the most work. You do not want to do this kind of business logic on the right hand side of your rule. There's a whole lot of ways you could go about checking that all the elements are the same -- if you've implemented equals/hashCode you could just shove everything into a set and confirm that the length of the set is still the length of the list; you could invert the rule to instead check for at least one item that's different; you could use accumulate or collect; ...
Finally --
- Avoid saliences. They're bad design. Your rules should stand alone. You only need saliences here because your third rule sets both true and false. If instead you defaulted to true and then used the rules to override it to false, you could get away with having absolutely no saliences at all.
- It's very unusual to use primitives for a global variable. I'm frankly not convinced that this will even work with a primitive. Globals work because the object is passed in by reference, and updated in the rules, and therefore the caller which retains the reference to the object will get the updated value. That doesn't work with primitives.
rule "Check for list not equal to two elements"
salience 1
when
PurchaseRequest($purchases: purchases != null)
List(size != 2) from $purchases
then
drools.getKieRuntime().setGlobal("eligibleForRefund", false);
end
rule "Check for two purchases"
salience 1
when:
PurchaseRequest( $purchases: purchases != null)
List( size != 2 ) from collect( Purchase(status == "Approved") from $purchases)
then
drools.getKieRuntime().setGlobal("eligibleForRefund", false);
end
// I've no idea what data type `getCost()` returns; I'm assuming "String"
rule "Check for the same purchases"
when:
PurchaseRequest($purchases: purchases != null)
// accumulate all of the costs into a set. if all costs are the same, set size = 1
$costs: Set() from accumulate( Purchase( $cost: cost ) from $purchases;
collectSet($cost))
then
drools.getKieRuntime().setGlobal("eligibleForRefund", $costs.size() == 1);
end