When building applications using Madura Rules we have some choices when defining the data for the decision tables. This is the data that tells the rules what combinations of settings work together. In the pizza demo this tells us, for example, what toppings and bases go with what pizza sizes. The data is not usually very large and is only ever read, not written.
In the pizza demo this data is held in an XML file stored as a resource on the classpath.
There are two interesting issues to solve here.
- Data stored in XML is all very well, but it is not so easy to maintain. This is especially true if you have multiple operators working on it at once.
- There is no ability to version the data. Everyone using the application sees the same combinations and options, always the latest one. What if they want to see how things were last week? For example they might have saved a shopping cart from last week and want to order this week and the data changed meanwhile.
As long as we keep things in XML we can solve the second problem quite easily with Madura Bundle. The XML file in the pizza demo is just a resource and distributing resources is supported by Madura Bundles. The idea here is that the application selects one of the available bundles (and the XML file is in the bundle). Extending the shopping cart example, when last week’s shopping cart is picked it would hold the id of the bundle used to create it, and the application would pick that bundle before restoring the shopping cart. Everything would then work as normal.
You can add new bundles any time and new shopping carts would always pick the most recent bundle. Sometimes there would be a reason for an old shopping cart to run under the latest bundle, perhaps if we decided the old bundle was no longer valid for the business. Maybe it holds prices we don’t want to support now.
The bundle can also hold rules and code if you want. You could put as much of the application you want into the bundle. Just where the balance should be is up to you.
Now, about that XML. Could we use a database? Actually yes. HSQL has a memory-only database option, including one that we can load from data held on the classpath. Naturally it is read-only and naturally you don’t want to hold gigabytes of data in it. But you can use ordinary JDBC to access it, and that means you can use more interesting things like JPA on top of that.
To use this with Madura Rules you’d need to write some Java, namely you’d need to extend the AbstractDecisionTable to support the actual database structure you actually have. This is the simple bit. You define the data source like this:
<property name=”driverClassName” value=”org.hsqldb.jdbcDriver” /> <property name=”url” value=”jdbc:hsqldb:res:/testdb” />
<property name=”username” value=”sa” />
<property name=”password” value=”” />
This assumes you have a file called testdb.script in the top of your classpath. You can optionally add testdb.properties. HSQL creates these files if you create a database using a URL jdbc:hsqldb:file:testdb (testdb can have a directory in front of it, this example uses the cwd).
H2 has a similar option, but I haven’t used that yet so I’m not clear on the details.
Can we put the database into a Madura Bundle? There wouldn’t be much point to this post if we couldn’t, I guess. So here’s how.
All you need to do is define the data source inside the bundle. I actually defined the data source, JPA entity manager and a DAO class as beans in the bundle. Note that the classes for these are on the classpath of the application. You don’t have to bundle those classes (this is one of the differences between Madura Bundles and OSGi). The DAO class is exposed to my main application.
Because HSQL remembers the database name and assumes a request to open a database with the same name is the same database, you do need to ensure each bundle calls the database by a different name. This is simple enough
Using the bundle.name symbol like this means the file this data source looks for is (in my case) bundle-1.0-testdb, bundle-2.0-testdb and so on. I also have to rename my testdb.script file to bundle-1.0-testdb.script etc.
Now this all works just fine in a simple test case except that HSQL adds a ‘/’ to the front of the file name and Madura Bundles does not like this. I’ve added a small patch to Madura Bundles to overcome this, but it isn’t quite enough to justify a release just yet. It will be in version 3.5.