A Simple Rule Engine

Published: 4:08 PM GMT+12, Saturday, 6 August 2005 under: technology
java  rules  jsr94 

There's been alot of talk lately about rules engines like drools, and especially the work on JSR-94 and javax.rules, and although I've not fully looked into any of the current solutions out there, I found myself looking at some code yesterday which was a mess of if this but not that but also this then do that which just screamed at me to clean it up.

At this point in time I wasn't really interested in standards, or adding yet another projects dependancies, so I did what everyone does - I wrote my own ;)

I started with several simple desires:
  1. No additional dependencies.
  2. Interface driven
  3. Easily testable.
So we kick this off with a simple TestNG test case:
 1 /**
2 * @testng.test
3 */
4 public class TestRulesEngine {
5  public void testGetRuleset() {
6 assert null != SpringRuleManager.getInstance().getRule("test-rules");
7 } 
8
}
Now we have a failing test that refers to a SpringRuleManager singleton which gives us a rule based on a name. We continue on by making the test pass, ultimately coming up with three key interfaces:
 1 public interface RuleManager {
2 RuleSet getRule(String name);
3 }
 1 public interface RuleSet {
2  void check(Object o, Runnable onSuccess);
3 }
4
 1 public interface Rule {
2  void check(Object o);
3 }
Without going into details (another post, another time) we now have three interfaces, a RuleManager, RuleSet, and Rule. The SpringRuleManager referenced in the test is implemented as a singleton which loads rule definitions from a Spring context "/applicationRules.xml" classpath resource:
 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
3 <beans>
4 <bean id="test-rules" class="SimpleRuleSet">
5 <constructor-arg>
6   <list>
7   <bean class="NameIsMarkRule"/>
8   </list>
9   </constructor-arg>
10   </bean>
11 </beans> 
This configuration defines one rule set called "test-rules" which contains one rule "NameIsMarkRule", which is implemented:
 1 public class NameIsMarkRule implements Rule {
2  public void check(Object o) {
3  assert o instanceof String;
4 String anotherString = (String) o;
 5 assert "mark".equalsIgnoreCase(anotherString);
6 }
7 }
This fairly simple rule checks if the object being tested is actually a String, and checks that it is "mark". Putting everything together, this rule can be checked using a very simple API:
 1 if (SpringRuleManager.getInstance().check("test-rules", "mark")) {
2 // The rule passed, continue with whatever logic we wanted
3 } 
Currently, unlike drools or other rule engines, my rules system here doesn't provide any explicit consequence clause for updating the object, leaving that up to the calling application code, it's a no brainer to add it in but currently I don't have any need for this.

The next step should be to rework the engine to conform to JSR-94 where possibe...

Comments (2)

Although not very correct. OSWorkflow can be use as a form of rule engine

left by Ian Lim . Sunday, 7 August 2005 3:25 PM

Gah - stupid "copy as html" screwed up my code formatting. And my god what ugly looking HTML it generated :(

left by Mark Derricutt . Saturday, 6 August 2005 6:09 PM
Add Comment