A Simple Rule Engine
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:
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:
- No additional dependencies.
- Interface driven
- Easily testable.
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...
The next step should be to rework the engine to conform to JSR-94 where possibe...
Comments (2)
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
Although not very correct. OSWorkflow can be use as a form of rule engine