Business Rules Engines
It seems that every company I join, dabbles and toys with the idea
of using a rules engine. The idea makes sense, as we've been trying
to get the suits to clarify their needs ever since we invented SQL††SQL was originally expected for business people to use without bothering programmers. Don't expect a rules engine to fare any better .
But what product should you use?
Jess and others seem overly complex… besides, I prefer to look at open source software first.
Drools has a high-level of hype, but if I have to program
in XML one more time, I swear, I'll…
I remember studying Prolog back in college, and while I could see its
power, it is hobbled by its lack of the basics, like file I/O, networking,
and user interface support. However, as a rules engine component
embedded inside a Java application, may result in a sweet, symbiotic relationship.
We could have a Rules.java
class‡‡By encapsulating the Prolog system with our own Rules
class, we can swap out Prolog implementations. , that
we should store in a global collection of singletons or wire up in an IoC container:
Rules engine = new Rules("my-rules.plog");
// We could then add or set data values available to it:
engine.setModel(data);
// Later we could then use Prolog query strings:
Hashtable results = engine.query("recommendProduct(X).");
results.get("X");
To play with this idea, let's build a little sandbox.
First, let's try out the JLog implementation, by adding the
following dependency to a Maven pom.xml
file:
<dependency>
<groupId>net.sf.jlogic</groupId>
<artifactId>jlog</artifactId>
<version>1.3.6</version>
</dependency>
Now, we'll create our Rules.java
class, which is pretty simple stuff
since it is little more than an encapsulating wrapper around the jPrologAPI
.
Our constructor will take a filename to a Prolog file. We should be able to
accept both a string and a java.io.File
, and we might as well create some
getters and setters, but I'll let you flesh that out:
public class Rules {
jPrologAPI api;
public Rules(String filename) throws IOException {
setFile( new File(filename) );
}
public void setFile(File source) throws IOException {
FileInputStream in = new FileInputStream(source);
api = new jPrologAPI(in);
in.close();
}
}
We want to be able to set up some extra data that the rules can work on.
Things like shopping cart contents, customer details or product information
may change often when the rules wouldn't, so we'll add a private field and more
setters and getters:
Hashtable model;
public void setModel(Map data) {
if (model == null)
model = new Hashtable();
model.putAll(data);
}
Finally, we accept a query string and return back a hash of the results:
public Hashtable query(String query) {
return api.query(query, model);
}
Sure, we could make this class more complete (see the entire source),
but this will get us started. Let's make the hello world of Prolog, by
creating a test1.plog
file:
mortal(X) :- person(X).
person(socrates).
The first line is a rule (which uses the rule operator :-
and ends with a full stop).
This rule says that anyone that is a person
is also mortal
.
The second line defines socrates
as a mortal
.
Let's write a test to verify things:
public void testBasics() throws Exception
{
File source = new File(path, "test1.plog");
Rules engine = new Rules(source);
Hashtable results = engine.query("mortal(X).");
assertEquals("'socrates'", results.get("X"));
}
Pretty easy to build the basics. Now, I'll need to build something
more interesting, but that will have to wait until this weekend.
Tell others about this article: