Why is JSR-94 (Java Rule Engine API) ill-designed?
Posted by Mike Haller
on Sunday, October 26. 2008
at 19:38
in Java
I'm currently trying to implement JSR-94. I downloaded the TCK (Technology Compatibility Kit) and let it run. For each failing test case, I implemented a bit more of my JSR94 implementation until all the test cases passed. So, right now, all the tests pass but it's still missing a lot. On the road, I found the some things about JSR-94 which could have been done much better by the initial group designing the API.
Following an ancient ill-design: JDBCWhen it comes to registration of the rule service engines (called RuleServiceProvider in JSR94), the "expert group" followed the design of JDBC's DriverManager. JDBC drivers are registered by issueing a Class lookup on their driver's name using reflection and the Driver's will statically register themselves at Java's DriverManager.
User does: Class.forName("org.h2.Driver");
org.h2.Driver does: DriverManager.registerDriver(this);
As the JSR94 JavaDoc API mentions that it uses the same technique and that user's should use Class.forName(), i had to implement it the same way. I implemented the RuleServiceProvider and added the following static block,
to register my RuleServiceProviderImpl implementation with the RuleServiceProviderManager:
public class RuleServiceProviderImpl
extends RuleServiceProvider {
public static final String RULE_SERVICE_PROVIDER_URI
= "de.visualrules.jsr94.RuleServiceProvider";
{
try {
RuleServiceProviderManager.
registerRuleServiceProvider(
RULE_SERVICE_PROVIDER_URI,
RuleServiceProviderImpl.class);
} catch (ConfigurationException e) {
throw new RuntimeException(e);
}
}
That did not work and lead to a StackOverflowException. Removing the static registration block again left my code in the state where the client (a JUnit TestCase in my case) has to know that he needs to call RuleServiceProviderManager.registerRuleServiceProvider(). I wonder why the client code needs to know about that anyway.
As we've learned in the past 10 years, static registries suck. Especially when it comes to complex scenarios like dynamic class loading and highly dynamic component containers like OSGi. It's even bad for testing purposes. Where do you put that Class.forName in your code? Think about it. You will probably use a static block in your main class. And there, you'd need to catch the javax.rules.ConfigurationException. What do you do with it - in a static block, where the application itself not even is startup up. You can't do anything meaningful at that time.
Input data has no name
I don't know much about RETE-based rule engines. But i know enough frameworks and engines which get some sort of parameters from the outside world that I know that parameters always have a name and a value. Not so with JSR94. You have parameters, indeed. They're free-floating objects, but without any means of meta-information such as a simple name.
The JSR94 API of javax.rules.StatelessRuleSession:
java.util.List executeRules(java.util.List objects)
Dear god, please enlighten me. I need to know what the "expert group" thought when they designed that. Why didn't they come up with something more useful, like using a Map:
java.util.Map executeRules(java.util.Map parameters)
And besides, there doesn't seem to be any way to get the original source code of the JSR94 API. I can find documentation though. There's no artifact in the Maven Repository. Sorry JSR94 guys. You could have done much better. JSR94 will disappear because nobody likes to work with it.
Like JBoy writes on his blog:
Being able to change engine implementation is a nice design approach, but as of today this specification is limited by the fact that there is still no standard to exchange rule definition between engines. So rule written for one engine can not be used by another one. This dramatic limitation is undermining the use of JSR94. And i'm still surprise to see architect asking compliance to it.
Indeed, I ask myself, too, why I should adhere to this so-called standard when there is so little about it. It's nothing more than two or three interfaces and a factory. It's just not mature enough to be of any help. There's not enough meat in there to feed my lust.
Redhill wrote four years ago: "JSR-94 Not Useless But Certainly Trivial". And there hasn't been any evolution since then.
Even Daniel Selman, who was the inventor os JSR-94, doesn't write about JSR-94. Perhaps it was just a Marketing Gag all along.
[1] JSR-94 Website: http://www.jcp.org/en/jsr/detail?id=94
[2] Daniel Selman: http://blogs.ilog.com/brms/author/dselman/
[3] JavaBoutique Tutorial: http://javaboutique.internet.com/tutorials/rules_engine/index-2.html
[4] JBoy's Blog: http://www.agileitarchitecture.com/2008/10/jsr94-over-visioned-java-standard.html
[5] Red Hill: http://www.redhillconsulting.com.au/blogs/simon/archives/000191.html

I remember some of it and I agree that some parts are not well defined and awkward.
In my opinion you can certainly find passages that are geared toward a certain rule engine technology, so one can guess who was the driving force behind the specification.
Looking at the situation today, how important is it in reality? From my humble knowledge customers are asking if we are JSR94 compatible but it is a point on the checklist which can be ticked off.
So what use is this API anyway? Has anybody heard of someone being able to exchange a rule engine because of JSR94?
Can we live without this specification? I would have answered yes, but maybe someone out there has a different opinion.
Of course, no spec is able to fulfill any requirements of all possible implementations. However, JSR-94 is one of those specs which won't survive.