Howardism Musings from my Awakening Dementia
My collected thoughts flamed by hubris
Home PageSend Comment

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:
Click here to submit this page to Stumble It