Rule Templates

Related to decision tables (but not necessarily requiring a spreadsheet) are "Rule Templates" (in the drools-templates module). These use any tablular data source as a source of rule data - populating a template to generate many rules. This can allow both for more flexible spreadsheets, but also rules in existing databases, for instance (at the cost of developing the template up front to generate the rules).

With Rule Templates the data is separated from the rule and there are no restrictions on which part of the rule is data-driven. So whilst you can do everything you could do in decision tables you can also do the following:

A decision table-like example

As an example, a more classic decision table is shown, but without any hidden rows for the rule meta data (so the spreadsheet only contains the raw data to generate the rules).

See the "ExampleCheese.xls" in the examples download for the above spreadsheet.

If this was a regular decision table there would be hidden rows before row 1 and between rows 1 and 2 containing rule metadata. With rule templates the data is completely separate from the rules. This has two handy consequences - you can apply multiple rule templates to the same data and your data is not tied to your rules at all. So what does the template look like?

1  template header
2  age
3  type
4  log
5
6  package org.drools.examples.templates;
7
8  global java.util.List list;
9
10 template "cheesefans"
11
12 rule "Cheese fans_@{row.rowNumber}"
13 when
14    Person(age == @{age})
15    Cheese(type == "@{type}")
16 then
17    list.add("@{log}");
18 end
19
20 end template
	

Referring to the above:

Line 1: all rule templates start with "template header"
Lines 2-4: following the header is the list of columns in the order they appear in the data. In this case we are calling the first column "age", the second "type" and the third "log".
Lines 5: empty line signifying the end of the column definitions
Lines 6-9: standard rule header text. This is standard rule DRL and will appear at the top of the generated DRL. Put the package statement and any imports and global definitions
Line 10: The "template" keyword signals the start of a rule template. There can be more than one template in a template file. The template should have a unique name.
Lines 11-18: The rule template - see below
Line 20: "end template" signifies the end of the template.

The rule templates rely on MVEL to do substitution using the syntax @{token_name}. There is currently one built-in expression, @{row.rowNumber} which gives a unique number for each row of data and enables you to generate unique rule names. For each row of data a rule will be generated with the values in the data substituted for the tokens in the template. With the example data above the following rule file would be generated:

package org.drools.examples.templates;

global java.util.List list;

rule "Cheese fans_1"
when
  Person(age == 42)
  Cheese(type == "stilton")
then
  list.add("Old man stilton");
end

rule "Cheese fans_2"
when
  Person(age == 21)
  Cheese(type == "cheddar")
then
  list.add("Young man cheddar");
end

The code to run this is simple:

//first we compile the spreadsheet with the template
//to create a whole lot of rules.
final ExternalSpreadsheetCompiler converter = new ExternalSpreadsheetCompiler();
//the data we are interested in starts at row 2, column 2 (e.g. B2)
final String drl = converter.compile(getSpreadsheetStream(), getRulesStream(), 2, 2);

We create an ExternalSpreadsheetCompiler object and use it to merge the spreadsheet with the rules. The two integer parameters indicate the column and row where the data actually starts - in our case column 2, row 2 (i.e. B2)