Tuesday 19 July 2011

Rules Engine on mobile platform : Getting JRuleEngine to do what it promised ..

During my work on rule engine on mobile platform, I came across this JRuleEngine which I briefly touched upon, in my last blog here. In there, I mentioned that I extended JRuleEngine to support multiple "facts" of same type. I thought it would be worth-while to publish what and how I did it, so this blog.


The last released ( 2008 ? ) version of JRuleEngine said in the documentation that it supports multiple facts of same type, but it actually didn't. All the facts which are loaded in the working memory are stored in a map with the getClass().getName() as key, which obviously means that only one fact of a "type" can be stored since the key in the map must be unique. So the last fact that was fed into working memory always wins, and is considered for rules execution. This is not what ( and most of us ) really wanted. 


To overcome this issue, there were a few considerations that were needed. 
(a)  Working memory should be capable of loading multiple facts of same type
(b)  Rules engine should be able to query for and receive an array of matching facts
(c)  The action/s should be able to act on all the matching facts
(d)  The result should be able to return all the facts
(e)  This behavior should be followed by all rules in the rule file


To take care of this issue, first thing required was to store the facts with a unique identifier, and so the engine would need a method to be called upon the facts which returned a unique identifier.  To achieve this, I created an abstract class named "ParentObject" which defined a "getId()" method and inherited all the facts from this ParentObject. So all the facts had to provide implementation for the getId() method. In my case, this method just returns the unique id field ( primary key in database ). But this id alone may not be unique across different types of facts, so while adding these facts into the working memory map, I appended getClass().getName() with the returned value from getId() to make this instance entry really unique.


Fact object : 
-----------------
public class FactObject extends ParentObject {
...
...
    public int getId() 
    {
         return this.id;
    }
...
...
}


Rule Engine :
 -----------------

public class StatefulRuleSessionImpl implements StatefulRuleSession {
...
...
if (object instanceof ParentObject)
{
    workingMemory.put(object.getClass().getName()+"_"+((ParentObject)object).getId(),object);
}

...
...

}


I then wrote a method to retrieve all the matching facts from the working memory. So whenever executeRules() is called, the engine now calls this new method that returns all the facts matching the "if" condition/s in the rule/s.


To see if the fact passes the constraint in the rule, the rule engine first gets the matching facts from working memory, executes the LHS in the constraint, gets the return value and then parses the RHS of the constraint in the rule. It then compares the return value from the method call on fact with the result of parsing RHS, and decides if the facts pass the constraint. So on the same lines, my code gets all the matching facts from the working memory, stores the fact id and the result for each fact from LHS expression in to a map, and then later loops through the map to filter out the facts which do not pass the first constraint. 


This check is then recursively done for each constraint, one by one, leaving behind only the facts which match all the constraints in the rule.


Then comes the "actions" part.  The action needs to be executed on all the facts which matched all the constraints in last step, so my extended code now evaluates the LHS part of the action once and then in loop, executes the RHS part of the action for all the facts that passed last step.


The rule engine then repeats this process for all actions within the rule, for all rules in the rules file. 


The result, by default, gathers all facts anyway, so didn't have to do anything special there.

2 comments:

  1. Hi Abhay, I'm trying to follow the steps you posted here to port JRuleEngine to Android (http://tech-voyage.blogspot.com.es/2011/06/getting-rule-engine-to-work-on-mobile.html). Sadly I suffer from several problems in the application architecture, and I think I'm making progress blindly.

    Is your code available for download?

    Thank you!

    ReplyDelete
    Replies
    1. HI Abhay,
      I gone through the blog.It is really nice. It will be really good when we go through with full sample code.

      Delete