Search code examples
javadroolsguvnor

Access to Drools returned fact object in Java Code


I have a drools rule created via the Guvnor console and the rule validates and inserts a fact into the working memory if conditions were met. The rule is:

    1. | rule "EligibilityCheck001" 
    2. |     dialect "mvel" 
    3. |     when 
    4. |         Eligibility( XXX== "XXX" , YYY== "YYY" , ZZZ== "ZZZ" , BBB == "BBB" ) 
    5. |     then 
    6. |         EligibilityInquiry fact0 = new EligibilityInquiry(); 
    7. |         fact0.setServiceName( "ABCD" ); 
    8. |         fact0.setMemberStatus( true ); 
    9. |         insert(fact0 ); 
   10. |         System.out.println( "Hello from Drools"); 
   11. | end 

Java code that executes the rule is as follows

RuleAgent ruleAgent = RuleAgent.newRuleAgent("/Guvnor.properties");
RuleBase ruleBase = ruleAgent.getRuleBase();
FactType factType = ruleBase.getFactType("mortgages.Eligibility");

Object obj = factType.newInstance();
factType.set(obj, "XXX", "XXX");
factType.set(obj, "YYY", "YYY");
factType.set(obj, "ZZZ", "XXX");
factType.set(obj, "BBB", "BBB");

WorkingMemory workingMemory = ruleBase.newStatefulSession();
workingMemory.insert(obj);
workingMemory.fireAllRules();
System.out.println("After drools execution");
long count = workingMemory.getFactCount();
System.out.println("count " + count);

Everything looks great with the output as below:

Hello from Drools
After drools execution
count 2

I cannot seem to find a way to get the EligibilityInquiry fact object back in my Java code and get the attributes set in the rule above (serviceName and status). I have used the StatefulSession approach.

The properties file has the link to the snapshot with basic authentication via username and password. There are 2 total facts: EligibilityInquiry and Eligibility.

I am fairly new to drools and any help with the above is appreciated.


Solution

  • (Note: I fixed the order of statement, a typo ("XX") and removed the comments from the output. Less surprise.)

    This snippet assumes that EligibilityInquiry is also declared in DRL.

    FactType eligInqFactType = ruleBase.getFactType("mortgages", "EligibilityInquiry");
    Class<?> eligInqClass = eligInqFactType.getFactClass();
    ObjectFilter filter = new FilterByClass( eligInqClass );
    Collection<Object> eligInqs = workingMemory.getObjects( filter );
    

    And the filter is

    public class FilterByClass implements ObjectFilter {
        private Class<?> theClass;
        public FilterByClass( Class<?> clazz ){
            theClass = clazz;
        }
        public boolean accept(Object object){
            return theClass.isInstance( object );
        } 
    }
    

    You might also use a query, which takes about the same amount of code.

    // DRL code
    query "eligInqs" 
        eligInq : EligibilityInquiry()
    end
    
    // after return from fireAllRules
    QueryResults results = workingMemory.getQueryResults( "eligInqs" );
    for ( QueryResultsRow row : results ) {
        Object eligInqObj = row.get( "eligInq" );
        System.out.println( eligInqClass.cast( eligInqObj ) );
    }
    

    Or you can call workingMemory.getObjects() and iterate the collection and check for the class of each object.

    for( Object obj: workingMemory.getObjects() ){
        if( obj.isInstance( eligInqClass ) ){
            System.out.println( eligInqClass.cast( eligInqObj ) );
        }
    }
    

    Or you can (with or without inserting the created EligibilityInquiry object as a fact) add the fact to a global java.util.List eligInqList and iterate that in your Java code. Note that the API of StatefulKnowledgeSession is required (instead of WorkingMemory).

       // Java - prior to fireAllRules
       StatefulKnowledgeSession kSession() = ruleBase.newStatefulSession();
    
       List<?> list = new ArrayList();
       kSession.setGlobal( "eligInqList", list );
    
       // DRL
       global java.util.List eligInqList;
    
       // in a rule
       then
           EligibilityInquiry fact0 = new EligibilityInquiry(); 
           fact0.setServiceName( "ABCD" ); 
           fact0.setMemberStatus( true ); 
           insert(fact0 );  
           eligInqList.add( fact0 ); 
       end
    
       // after return from fireAllRules
       for( Object elem: list ){
        System.out.println( eligInqClass.cast( elem ) );
       }
    

    Probably an embarras de richesses.