Search code examples
javaspring-bootdrools

How to pass parameter value for rule condition in DRL file?


I am new in Drools. I want to pass parameter for rule condition in rule.drl file.

Currently i have code like this :-

rule "PREPAID TOP UP LIMIT" salience 1

when
cardObject : Card(cardType=="prepaid" && loadCash > 25000);
then
cardObject.setTransactionResposne(false);
cardObject.setMessage("Top up limit exceeds ");
end;

As you can see in this code cardType and loadCash is compare with "prepaid" and 25000 respectively with static value. But i want initiate this static value from java classes.

So, How can i pass this parameter. Please share some solution.


Solution

  • You basically have two options:

    1. Pass the conditions into working memory.
    2. Declare the conditions as global variables.

    Global variables are generally frowned upon, but I will include this for completeness.


    For the first option, passing the conditions into working memory, I would suggest creating a simply object which has these conditions declared along with appropriate getters/setters.

    For example:

    public class CardLimits {
      private String type;
      private Integer limit;
      // getters and setters here
    }
    

    You would pass the CardLimits instance (or instances if you have multiple types) into working memory alongside your Card instance. Then your rule could be as follows:

    rule "PREPAID TOP UP LIMIT" 
    salience 1
    when
      CardLimits( $max: limit != null, $type: type == "prepaid" )
      cardObject : Card( cardType == $type && loadCash > $max);
    then
      cardObject.setTransactionResposne(false);
      cardObject.setMessage("Top up limit exceeds ");
    end
    

    (Minor nitpick: the semi-colon you have after end shouldn't be there. Also you've spelled 'response' wrong on the right hand side.)

    The CardLimits instance would be passed into the rules alongside your Card instance like this:

    KieSession kieSession = ...; 
    
    Card card = ...; // the Card you are passing into the rules
    CardLimits limits = ...; // the limits
    
    kieSession.insert( card ); 
    kieSession.insert( limits ); 
    kieSession.fireAllRules();
    

    Note that for this structure, you can have a single rule for multiple types of limits.

    So, for example, let's say you had two types of cards "prepaid" and "gift", with different CardLimits instances describing their limits. You could then have a single rule to handle both like this:

    rule "ANY TOP UP LIMIT" 
    salience 1
    when
      CardLimits( $max: limit != null, $type: type ) // no restriction on 'type'
      cardObject : Card( cardType == $type && loadCash > $max); 
    then
      cardObject.setTransactionResposne(false);
      cardObject.setMessage("Top up limit exceeds ");
    end
    

    I would also suggest using an enum instead of a String for the card type.

    By passing in an object, you also have the freedom to add additional conditions in the future. For example, let's say you want to refuse top-ups if the card expires within a certain number of days -- you can add that to your conditions object as needed.


    For completeness's sake, your alternative is to use globals. This is generally something you want to avoid, for the same reasons we try to avoid global variables in most languages unless there is no other choice. This was a pretty common practice when I first started doing Drools (back in Drools 5) but has since generally fallen out of favor.

    global Integer max;
    global String type;
    
    rule "PREPAID TOP UP LIMIT" 
    salience 1
    when
      cardObject : Card( cardType == type && loadCash > max);
    then
      cardObject.setTransactionResposne(false);
      cardObject.setMessage("Top up limit exceeds ");
    end
    

    This will limit you to only a single type and max value for all rules. So you can't process multiple cards at the same time.

    You set globals when you call the rules:

    KieSession kieSession = ...; 
    
    Card card = ...; // the Card you are passing into the rules
    
    // set the globals
    kieSession.setGlobal( "max", (Integer)25000 );
    kieSession.setGlobal( "type", "prepaid" );
    
    kieSession.insert( card ); 
    kieSession.fireAllRules();
    

    I would not recommend using Globals for this. I only include this possibility because it is something you could do.