How to define and initialize variables in drools rule

12,165

While I don't know what the rule should evaluate, this is more like the style your rule should be written. I don't know how LicenseCredential is declared, nor do I know those Util.getXyz functions, so this may not work. Also, I've skipped the last condition.

rule "Renewal alert for 60 days"
when
licenseCredential : LicenseCredential(
      $courseCompletionDate : courseCompletionDate,
      $renewalDeadlineDay : renewalDeadlineDay == "0",
      $renewalDeadlineMonth : renewalDeadlineMonth == "0",
      $currentDate : currentDate after 
              getDate(2, $courseCompletionDate.getDate(),
                         $courseCompletionDate.getMonth()+1 ),
              && before
              getDate(1, $courseCompletionDate.getDate(),
                         $courseCompletionDate.getMonth()+1 ) )
then
    System.out.println("Rule For 60 Days Called");      
    processData(licenseCredential, learnerCsvFileWriter, 2);
end
Share:
12,165
Basit
Author by

Basit

A solution-oriented well balanced technical IT Professional with a rich experience of 8 years + in software development covering multiple technologies. I keep atop of new developments within the industry and can adapt quickly to new coding conventions. I am happy working independently or in a close team environment, and apply a positive attitude to every task I undertake. I possess a broad range of technical skills which I refresh on a regular basis, allowing me to respond to new issues with considerable speed.

Updated on June 04, 2022

Comments

  • Basit
    Basit almost 2 years

    I am using drools 6.1. I have a drool file. I want to do something like this.

    import static com.softech.vu360.autoalert.util.Utility.getCurrentDate;
    import static com.softech.vu360.autoalert.util.Utility.getDate;
    import static com.softech.vu360.autoalert.util.Utility.getMonthNameFromInt;
    import static com.softech.vu360.autoalert.util.Utility.getExpiryDate;
    import static com.softech.vu360.autoalert.util.Utility.getEmailDate;
    import static com.softech.vu360.autoalert.util.Utility.getWeekOfYear;
    import com.softech.vu360.autoalert.model.LicenseCredential;
    import com.softech.vu360.autoalert.model.Learner;
    import com.softech.vu360.autoalert.CsvFileWriter;
    import java.time.LocalDate;
    import java.util.Date;
    
    global com.softech.vu360.autoalert.CsvFileWriter learnerCsvFileWriter;
    
    function void processData(LicenseCredential licenseCredential, CsvFileWriter learnerCsvFileWritern, LocalDate expiryDate, LocalDate emailDate){
    
        Learner learner = new Learner();
        learner.setFirstName(licenseCredential.getFirstName());
        ...
        learnerCsvFileWriter.add(learner);
    
    }
    
    rule "Renewal alert for 60 days"
    when
        licenseCredential : LicenseCredential()
    
        $courseCompletionDate : licenseCredential.getCourseCompletionDate()
        $renewalDeadlineDay : licenseCredential.getRenewalDeadlineDay()
        $renewalDeadlineMonth : licenseCredential.getRenewalDeadlineMonth()
        $currentDate : getCurrentDate()
        $dayOfMonth : $courseCompletionDate.getDate()
        $month : $courseCompletionDate.getMonth()
        $expiryDate : getExpiryDate(licenseCredential)
        $emailDate : getEmailDate(2, licenseCredential)
        $localDate : LocalDate.now()
        $intRenewalDeadlineDay : Integer.valueOf($renewalDeadlineDay)
        $intRenewalDeadlineMonth : Integer.valueOf($renewalDeadlineMonth)
    
        (
            eval($renewalDeadlineDay == "0" && $renewalDeadlineMonth == "0") && 
            eval($currentDate.after(getDate(2, $dayOfMonth, $month + 1))) && 
            eval($currentDate.before(getDate(1, $dayOfMonth, $month + 1 ))) &&
            eval(getWeekOfYear($localDate.toString()) == getWeekOfYear($emailDate.toString()))
         ) ||
        (
            eval($currentDate.after(getDate(2, $intRenewalDeadlineDay, $intRenewalDeadlineMonth))) &&
            eval($currentDate.before(getDate(1, $intRenewalDeadlineDay, $intRenewalDeadlineMonth))) &&
            eval(getWeekOfYear($localDate.toString()) == getWeekOfYear($emailDate.toString())) 
        )
    then
        System.out.println("Rule For 60 Days Called");      
        processData(licenseCredential, learnerCsvFileWriter, $expiryDate, $emailDate);
    end
    

    I want to declare local variables in my loop. LicenseCredential is a list basically. When I run this rule I get errors that

     text=Unable to resolve ObjectType 'licenseCredential.getCourseCompletionDate'], Message [id=2, level=ERROR, path=drools/rules/Rule.drl, line=71, column=0
       text=Unable to resolve ObjectType 'licenseCredential.getRenewalDeadlineDay'], Message [id=3, level=ERROR, path=drools/rules/Rule.drl, line=72, column=0
       text=Unable to resolve ObjectType 'licenseCredential.getRenewalDeadlineMonth'], Message [id=4, level=ERROR, path=drools/rules/Rule.drl, line=73, column=0
       text=Unable to resolve ObjectType 'getCurrentDate'], Message [id=5, level=ERROR, path=drools/rules/Rule.drl, line=74, column=0
       text=Unable to resolve ObjectType '$courseCompletionDate.getDate'], Message [id=6, level=ERROR, path=drools/rules/Rule.drl, line=75, column=0
       text=Unable to resolve ObjectType '$courseCompletionDate.getMonth'], Message [id=7, level=ERROR, path=drools/rules/Rule.drl, line=76, column=0
       text=Unable to resolve ObjectType 'getExpiryDate'], Message [id=8, level=ERROR, path=drools/rules/Rule.drl, line=77, column=0
       text=Unable to resolve ObjectType 'getEmailDate'], Message [id=9, level=ERROR, path=drools/rules/Rule.drl, line=78, column=0
       text=Unable to resolve ObjectType 'LocalDate.now'], Message [id=10, level=ERROR, path=drools/rules/Rule.drl, line=79, column=0
       text=Unable to resolve ObjectType 'Integer.valueOf'], Message [id=11, level=ERROR, path=drools/rules/Rule.drl, line=80, column=0
       text=Unable to resolve ObjectType 'Integer.valueOf'], Message [id=12, level=ERROR, path=drools/rules/Rule.drl, line=36, column=0
    

    If i put semicolon at the end of each variable like

    $courseCompletionDate : licenseCredential.getCourseCompletionDate();
        $renewalDeadlineDay : licenseCredential.getRenewalDeadlineDay();
        $renewalDeadlineMonth : licenseCredential.getRenewalDeadlineMonth();
        $currentDate : getCurrentDate();
        $dayOfMonth : $courseCompletionDate.getDate();
        $month : $courseCompletionDate.getMonth();
        $expiryDate : getExpiryDate(licenseCredential);
        $emailDate : getEmailDate(2, licenseCredential);
        $localDate : LocalDate.now();
        $intRenewalDeadlineDay : Integer.valueOf($renewalDeadlineDay);
        $intRenewalDeadlineMonth : Integer.valueOf($renewalDeadlineMonth);
    

    and run the rule I get errors that

    $renewalDeadlineDay cannot be resolved to a variable
    $renewalDeadlineMonth cannot be resolved to a variable
    $currentDate cannot be resolved
    $dayOfMonth cannot be resolved to a variable
    $month cannot be resolved to a variable
    $currentDate cannot be resolved
    $dayOfMonth cannot be resolved to a variable
    $month cannot be resolved to a variable
    $localDate cannot be resolved
    $emailDate cannot be resolved
    $currentDate cannot be resolved
    $intRenewalDeadlineDay cannot be resolved to a variable
    $intRenewalDeadlineMonth cannot be resolved to a variable
    $currentDate cannot be resolved
    $intRenewalDeadlineDay cannot be resolved to a variable
    $intRenewalDeadlineMonth cannot be resolved to a variable
    $localDate cannot be resolved
    $emailDate cannot be resolved
    $expiryDate cannot be resolved to a variable
    $emailDate cannot be resolved to a variable], Message [id=14, level=ERROR, path=drools/rules/Rule.drl, line=-1, column=0
    

    How can I define local variables. How can I do this ?

    Thanks

    --------------------------------- Edit

    Here how I am firing rules

    List<LicenseCredential> objectList = dao.select();
    BusinessRuleProcessor ruleProcessor = (BusinessRuleProcessor)context.getBean("businessRuleProcessor");
    ruleProcessor.configureAndApplyRulesOnObject(objectList);
    
    public class BusinessRuleProcessor {
        ....
        public void configureAndApplyRulesOnObject(List<LicenseCredential> objectList){
    
            statelessKieSession.setGlobal("learnerCsvFileWriter", csvFileWriter);
            statelessKieSession.execute(objectList);
    
        }
    }
    

    -------------- Edit2:

    Tried this and getting errors

    rule "Renewal alert for 60 days"
    when
        licenseCredential : LicenseCredential()
    
        $licenseCredentialCC : LicenseCredential($courseCompletionDate : courseCompletionDate)
        $licenseCredentialRDLD : LicenseCredential($renewalDeadlineDay : renewalDeadlineDay)
        $licenseCredentialRDLM : LicenseCredential($renewalDeadlineMonth : renewalDeadlineMonth)
        $licenseCredentialCD : LicenseCredential($currentDate : getCurrentDate())
        $licenseCredentialDOM : LicenseCredential($dayOfMonth : $licenseCredentialCC.getDate())
        $licenseCredentialM : LicenseCredential($month : $licenseCredentialCC.getMonth())
        $licenseCredentialEXD : LicenseCredential($expiryDate : getExpiryDate(licenseCredential))
        $licenseCredentialEMD : LicenseCredential($emailDate : getEmailDate(2, licenseCredential))
        $licenseCredentialLD : LicenseCredential($localDate : LocalDate.now())
        $licenseCredentialIRDLD : LicenseCredential($intRenewalDeadlineDay :  Integer.valueOf($licenseCredentialRDLD))
        $licenseCredentialIRDLM : LicenseCredential($intRenewalDeadlineMonth : Integer.valueOf($licenseCredentialRDLM))
    
        (
            eval($renewalDeadlineDay == "0" && $renewalDeadlineMonth == "0") && 
            eval($currentDate.after(getDate(2, $dayOfMonth, $month + 1))) && 
            eval($currentDate.before(getDate(1, $dayOfMonth, $month + 1 ))) &&
            eval(getWeekOfYear($localDate.toString()) == getWeekOfYear($emailDate.toString()))
         ) ||
        (
            eval($currentDate.after(getDate(2, $intRenewalDeadlineDay, $intRenewalDeadlineMonth))) &&
            eval($currentDate.before(getDate(1, $intRenewalDeadlineDay, $intRenewalDeadlineMonth))) &&
            eval(getWeekOfYear($localDate.toString()) == getWeekOfYear($emailDate.toString())) 
        )
    then
        System.out.println("Rule For 60 Days Called");      
        processData(licenseCredential, learnerCsvFileWriter, $expiryDate, $emailDate);
    end
    

    Errors:

    Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'autoalert-ksession-stateless': Cannot resolve reference to bean 'autoalert-kbase' while setting bean property 'kBase'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'autoalert-kbase': Invocation of init method failed; nested exception is java.lang.RuntimeException: Error while creating KieBase[Message [id=1, level=ERROR, path=drools/rules/Rule.drl, line=76, column=0
       text=Unable to Analyse Expression $licenseCredentialCC.getDate():
    [Error: unable to resolve method using strict-mode: com.softech.vu360.autoalert.model.LicenseCredential.getDate()]
    [Near : {... $licenseCredentialCC.getDate() ....}]
                                  ^
    [Line: 76, Column: 2]], Message [id=2, level=ERROR, path=drools/rules/Rule.drl, line=76, column=0
       text=Unable to analyze expression '$licenseCredentialCC.getDate()'], Message [id=3, level=ERROR, path=drools/rules/Rule.drl, line=77, column=0
       text=Unable to Analyse Expression $licenseCredentialCC.getMonth():
    [Error: unable to resolve method using strict-mode: com.softech.vu360.autoalert.model.LicenseCredential.getMonth()]
    [Near : {... $licenseCredentialCC.getMonth() ....}]
                                  ^
    [Line: 77, Column: 2]], Message [id=4, level=ERROR, path=drools/rules/Rule.drl, line=77, column=0
       text=Unable to analyze expression '$licenseCredentialCC.getMonth()'], Message [id=5, level=ERROR, path=drools/rules/Rule.drl, line=78, column=0
       text=Variables can not be used inside bindings. Variable   [licenseCredential] is being used in binding 'getExpiryDate(licenseCredential)'], Message [id=6, level=ERROR, path=drools/rules/Rule.drl, line=79, column=0
       text=Variables can not be used inside bindings. Variable [licenseCredential] is being used in binding 'getEmailDate(2, licenseCredential)'], Message [id=7, level=ERROR, path=drools/rules/Rule.drl, line=81, column=0
       text=Unable to Analyse Expression Integer.valueOf($licenseCredentialRDLD):
    [Error: unable to resolve method using strict-mode: java.lang.Integer.valueOf(com.softech.vu360.autoalert.model.LicenseCredential)]
    [Near : {... Integer.valueOf($licenseCredentialRDLD ....}]
                     ^
    [Line: 81, Column: 2]], Message [id=8, level=ERROR, path=drools/rules/Rule.drl, line=81, column=0
       text=Unable to analyze expression 'Integer.valueOf($licenseCredentialRDLD)'], Message [id=9, level=ERROR, path=drools/rules/Rule.drl, line=82, column=0
       text=Unable to Analyse Expression Integer.valueOf($licenseCredentialRDLM):
        [Error: unable to resolve method using strict-mode: java.lang.Integer.valueOf(com.softech.vu360.autoalert.model.LicenseCredential)]
        [Near : {... Integer.valueOf($licenseCredentialRDLM ....}]
                     ^
        [Line: 82, Column: 2]], Message [id=10, level=ERROR, path=drools/rules/Rule.drl, line=82, column=0
       text=Unable to analyze expression 'Integer.valueOf($licenseCredentialRDLM)'], Message [id=11, level=ERROR, path=drools/rules/Rule.drl, line=60, column=0
       text=[ function processDataprocessData (line:60): learnerCsvFileWriter cannot be resolved
     ]],     Message [id=12, level=ERROR, path=drools/rules/Rule.drl, line=68, column=0
           text=Rule Compilation error The import drools.rules.ProcessData cannot be resolved
    The operator + is undefined for the argument type(s) Object, int
    The operator + is undefined for the argument type(s) Object, int
    The method getDate(int, int, int) in the type Utility is not applicable for the arguments (int, Object, Object)
    The method getDate(int, int, int) in the type Utility is not applicable for the arguments (int, Object, Object)
    $expiryDate cannot be resolved to a variable
    $emailDate cannot be resolved to a variable], Message [id=13, level=ERROR, path=drools/rules/Rule.drl, line=-1, column=0
    

    Edit 3

    rule "Renewal alert for 60 days"
    when
        licenseCredential : LicenseCredential()
    
        $licenseCredential1 : LicenseCredential($courseCompletionDate : courseCompletionDate)
        $licenseCredential2 : LicenseCredential($renewalDeadlineDay : renewalDeadlineDay)
        $licenseCredential3 : LicenseCredential($renewalDeadlineMonth : renewalDeadlineMonth)
        $licenseCredential4 : LicenseCredential($currentDate : getCurrentDate())
        //$licenseCredential5 : LicenseCredential($dayOfMonth : licenseCredential.getCourseCompletionDate().getDate())
        //$licenseCredential6 : LicenseCredential($month : licenseCredential.getCourseCompletionDate().getMonth())
        //$licenseCredential7 : LicenseCredential($expiryDate : getExpiryDate(licenseCredential))
        //$licenseCredential8 : LicenseCredential($emailDate : getEmailDate(2, licenseCredential))
        $licenseCredential9 : LicenseCredential($localDate : LocalDate.now())
    
        (
            eval($renewalDeadlineDay == "0" && $renewalDeadlineMonth == "0") && 
            eval($currentDate.after(getDate(2, licenseCredential.getCourseCompletionDate().getDate(), licenseCredential.getCourseCompletionDate().getMonth() + 1))) && 
            eval($currentDate.before(getDate(1, licenseCredential.getCourseCompletionDate().getDate(), licenseCredential.getCourseCompletionDate().getMonth() + 1 ))) &&
            eval(getWeekOfYear($localDate.toString()) == getWeekOfYear(getEmailDate(2, licenseCredential).toString()))
         ) ||
        (
            eval($currentDate.after(getDate(2, Integer.valueOf($renewalDeadlineDay), Integer.valueOf($renewalDeadlineMonth)))) &&
            eval($currentDate.before(getDate(1, Integer.valueOf($renewalDeadlineDay), Integer.valueOf($renewalDeadlineMonth)))) &&
            eval(getWeekOfYear($localDate.toString()) == getWeekOfYear(getEmailDate(2, licenseCredential).toString())) 
        )
    
    then
        System.out.println("Rule For 60 Days Called");      
        processData(licenseCredential, learnerCsvFileWriter, 2);
    end
    

    ------------------ Edit 4

    Here is my LicenseCredential class

    public class LicenseCredential {
        private String learnerName;
        protected String firstName;
        protected String lastName;
        protected String learnerEmailAddress;
        private String userGUID;
        private Integer vu360UserId;
        private Integer courseId;
        protected String courseName;
        protected Date courseCompletionDate;
        private Integer credentialId;
        protected String officialLicenseName;
        private String shortLicenseName;
        private String renewalDeadLineType;
        private String renewalFrequency;
        private String renewalDeadlineDay;
        private String renewalDeadlineMonth; 
        private String hardDeadLineYear;
        private String staggeredBy;
        private String staggeredTo;
        protected String jurisdiction;
        protected String storefrontURL;
    
        //  setters and getters
    }
    

    Here is my Utility class

    public class Utility {
        public static Date getDate(int monthsToBeSubtracted, int date, int month) throws Exception{
            Calendar c = Calendar.getInstance();        
            c.set(Calendar.MONTH, month-1);
            c.set(Calendar.DATE, date);
            c.set(Calendar.MONTH, c.get(Calendar.MONTH)-monthsToBeSubtracted);
            c.set(Calendar.YEAR, getCurrentDate().getYear()+1900);
            return c.getTime();
        }
    
        public static Date getCurrentDate(){
            Calendar c = Calendar.getInstance();
            return c.getTime();
        }
    
        public static int getWeekOfYear(String date) throws Exception{
            Date currentDate = new SimpleDateFormat("yyyy-MM-dd").parse(date);
            String weekOfYear = new SimpleDateFormat("w").format(currentDate);
            return Integer.valueOf(weekOfYear);
        }    
    
        public static LocalDate getExpiryDate(LicenseCredential licenseCredential) {
    
            if (licenseCredential.getRenewalDeadlineDay() == "0" && licenseCredential.getRenewalDeadlineMonth() == "0") {
                Date courseCompletionDate = licenseCredential.getCourseCompletionDate();
                ...
                return expiryDate;
            } else {
                ...
                return expiryDate;
            }
    
        }
    }
    

    Previously this rule was like this

    rule "Renewal alert for 60 days"
    when
        licenseCredential : LicenseCredential()
        (
            eval(licenseCredential.getRenewalDeadlineDay() == "0" && licenseCredential.getRenewalDeadlineMonth() == "0") && 
            eval(getCurrentDate().after(getDate(2, licenseCredential.getCourseCompletionDate().getDate(), licenseCredential.getCourseCompletionDate().getMonth()+1))) && 
            eval(getCurrentDate().before(getDate(1, licenseCredential.getCourseCompletionDate().getDate(), licenseCredential.getCourseCompletionDate().getMonth()+1))) 
         ) ||
        (
            eval(getCurrentDate().after(getDate(2, Integer.valueOf(licenseCredential.getRenewalDeadlineDay()), Integer.valueOf(licenseCredential.getRenewalDeadlineMonth()) ))) &&
            eval(getCurrentDate().before(getDate(1, Integer.valueOf(licenseCredential.getRenewalDeadlineDay()), Integer.valueOf(licenseCredential.getRenewalDeadlineMonth() )))) 
        )
    then
        System.out.println("Rule For 60 Days Called");      
        processData(licenseCredential, "templates/Template.vm", "60Days", messageProducer);
    end