drools

How to grab the results and POJO class attributes in case Drools rule sets fails in JAVA


I am using Drools Rules for firing business case validations. For this I am creating POJO classes and setting the attributes values of the POJO classes and then firing the rules.

I can grab the results in case the rule gets passed as the action gets triggered and put the pass results of Drools execution summary in an excel file with corresponding POJO class attributes.

However, I cannot grab POJO class attributes and results for the failed rules as Drools does nothing( no action is invoked) in case rules are passed/met the condition.

Is there any way I can grab the Drools results and POJO class attributes in case the Drools rules fail in Java.?


Solution

  • If a rule does not match, it does not fire. There's no "result" to be grabbed. This is not a "failure", it's just a rule that doesn't match.

    Example:

    rule "USD"
    when
      $txn: Transaction( currency == "USD" )
    then
      $txn.convertCurrency();
    end
    

    Trivial example. If the 'transaction' is in USD, then convert currency. Let us say that the convertCurrency() method converts the transaction to GBP.

    If you pass in a POJO with Transaction( currency: "USD" ) and fire the rules, then you can observe the side effect in that the transaction, once the rules have been fired, is now in GBP. If, on the other hand, you pass in a POJO with Transaction( currency: "AUD" ), this rule will not fire and, in theory, the transaction will remain in AUD and not be converted.

    As the inputs do not meet the conditions of the rule, there is no match, and so the rule does not trigger and the consequences are not applied.

    There is nothing to see here, because nothing happened. Nothing happens because the rule does not match. It's like being told that an operation is a "no-op" and asking for a report about the results of that operation -- there's nothing to report because it's a no-op.


    Edge case is, of course, if you want consequences of no rules matching and therefore no rules firing. You can do this by setting a default state using a rule of higher salience so that it applies first, and then rely on a lower salience rule to override the condition if a rule does actually exist that matches the conditions presented by the inputs.

    Example:

    rule "Default shirt price"
    salience 10
    when
      $shirt: Shirt()
    then
      $shirt.setPrice(10)
    end
    
    rule "Red shirts"
    when
      $shirt: Shirt( color == "red" )
    then
      $shirt.setPrice(15);
    end
    
    rule "Blue shifts"
    when
      $shirt: Shirt( color == "blue" )
    then
      $shirt.setPrice(20);
    end
    

    Red shirts are $15, blue shirts are $20. All the rest are $10. The first rule has a higher salience (10) than the others which have default salience (0), so the first rule fires and sets the price for any given shirt to $10. More specific rules are lower salience and then override that price to $15 or $20 based on the color.

    In this case we use a rule to set a default state, and when we have a result that's still in that default state we'll no that no more rule triggered to match.


    The Drools lifecycle, greatly simplified, looks something like this:

    1. Sort all of the rules by salience.
    2. Iterate across each rule in order, considering its left-hand-side ("when") condition. If the condition is satisfied by the inputs, consider it a match. Collect all matches.
    3. Iterate across all matches in order, executing its right-hand-side ("then") consequences.

    Things get a little more complex with insert and update and the like, but this is basically it. There's no "failures" here, a rule either is a match or it isn't.

    You can create and apply a listener to the rule engine if you wish to do something with the raw matches, there are hooks for matches and match discards. Note that listeners will noticeably and negatively impact performance and should not be abused to do anything more than simple observation (and likely not on production systems.)