|
|
Rule Engine Introduction
A rule engine may be viewed as a sophisticated if/then statement interpreter.
The if/then statements that are interpreted are called rules.
The if portions of rules contain conditions such as shoppingCart.totalAmount > 100.
The then portions of rules contain actions such as recommendDiscount(5).
The inputs to a rule engine are a rule execution set and some data objects.
The outputs from a rule engine are determined by the inputs and may include the original input data objects with
possible modifications, new data objects, and side effects such as sendMail('Thank you for shopping').
There are many differences between rule engines, and the term is used extremely
loosely across the software industry.
JRuleEngine common features are:
- Act upon input objects to produce output objects.
Input objects are often referred to as facts and are a representation of the state of the application domain.
Output objects are often referred to as conclusions or inferences and are grounded by the
application into the application domain.
- The rule engine may execute actions directly (invoke methods of a class),
which affect the application domain, input objects, the execution cycle, etc.
One of the most common classes of rule engines is the forward-chaining rule engine.
Forward-chaining rule engines implement an execution cycle that allows the action of
one rule to cause the condition of other rules to become met. In this way, a cascade of
rules may become activated and each rule action executed. Forward-chaining rule
engines are suitable for problems that require drawing higher-level conclusions from
simple input facts.
JRuleEngine is based on a forward-chaining algorithm.
A rule is typically composed of two parts: a condition and an action.
When the condition is met, the action is executed.
In JRuleEngine a rule has the following format:
- a name
- a description
- a list of Assumption objects, having the format: "leftTerm" ["operator" "rightTerm"]
All assumptions are connected by an AND operator.
If assumption is in the form "leftTerm" "operator" "rightTerm", then the operator between left and right terms may be:
"=", "<>", "contains", "notcontains", "<", ">", "<=", ">=" where the last 4 are applied only on numeric terms.
If assumption has only leftTerm, then operator will be "exists" and the rule engine will control if leftTerm is contained
in the working memory.
A term may be a letteral (text, numeric value...) or a value obtained by a getter method of an object
(ex. Customer.getCreditLimit) or a variable, identified by the prefix ":" (for example: ":X").
Variables are allowed only as leftTerm and the operator must be "=" or "contains".
- a list of Action objects, having the format: "class.method" ["arg-1" "arg-2" ... "arg-N"]
i.e. the "method" of "class" object is invoked, where "class" is in working memory (an object passed to the rule engine)
or is created in that moment.
"method" may have zero to N arguments.
"arg-i" may be a term (see above).
A rule execution set is a collection of rules.
In JRuleEngine rules are org.jruleengine.rule.RuleImpl objects and they can be loaded in several ways:
- by reading an XML file (see XML Format)
- by creating RuleImpl objects, that can be retrieve from an external storage, like a database.
A rule session is a runtime connection between a client and a rule engine.
A rule session is associated with a single rule execution set.
A rule session may consume rule engine resources and must be explicitly released when the client no longer requires the
rule session.
There are two kind of rule sessions:
- A stateful rule session allows a client to have a prolonged interaction with a rule
execution set. Input objects can be progressively added to the session and output
objects can be queried repeatedly.
- A stateless rule session provides a high-performance and simple API that executes a
rule execution set with a List of input objects. Stateless rule session methods are idempotent.
|
Installation Instructions
JRuleEngine is based on two files:
- jsr94.jar
- jruleengine.jar
Add these files to your application classpath.
After that, you can use the library by instantiating a StatelessRuleSession or StatefulRuleSession.
JRule distribution includes the following directories:
- src - source file of JRuleEngine project.
- examples - examples of using JRuleEngine tool; it contains source and class files.
- lib - jar files.
- api - javadoc files.
|
Library Usage
After installing the library inside your application (see installation instructions above), you may:
- load and get the RuleServiceProvider object
- get the RuleAdministrator object
- load rules by creating a RuleExecutionSet object; this object may be created by means of (i) an XML file to load or (ii) using LocalRuleExecutionSetProvider.createRuleExecutionSet method, passing to it a list of RuleImpl objects
- create a RuleRuntime object
- create the StatelessRuleSession or StatefulRuleSession object from the RuleRuntime
- add some input objects to the rule session
- execute the rule engine, i.e. it fires valid rules, by executing actions specified in "then actions"
Example
try {
// Load the rule service provider of the reference implementation.
// Loading this class will automatically register this provider with the provider manager.
Class.forName( "org.jruleengine.RuleServiceProviderImpl" );
// get the rule service provider from the provider manager
RuleServiceProvider serviceProvider = RuleServiceProviderManager.getRuleServiceProvider( "org.jruleengine" );
// get the RuleAdministrator
RuleAdministrator ruleAdministrator = serviceProvider.getRuleAdministrator();
System.out.println("\nAdministration API\n");
System.out.println( "Acquired RuleAdministrator: " + ruleAdministrator );
// get an input stream to a test XML ruleset
InputStream inStream = new FileInputStream( "example1.xml" );
System.out.println("Acquired InputStream to example1.xml: " + inStream );
// parse the ruleset from the XML document
RuleExecutionSet res1 = ruleAdministrator.getLocalRuleExecutionSetProvider( null ).createRuleExecutionSet( inStream, null );
inStream.close();
System.out.println( "Loaded RuleExecutionSet: " + res1);
// register the RuleExecutionSet
String uri = res1.getName();
ruleAdministrator.registerRuleExecutionSet(uri, res1, null );
System.out.println( "Bound RuleExecutionSet to URI: " + uri);
// Get a RuleRuntime and invoke the rule engine.
System.out.println( "\nRuntime API\n" );
RuleRuntime ruleRuntime = serviceProvider.getRuleRuntime();
System.out.println( "Acquired RuleRuntime: " + ruleRuntime );
// create a StatefulRuleSession
StatefulRuleSession ruleSession =
(StatefulRuleSession) ruleRuntime.createRuleSession( uri,
new HashMap(),
RuleRuntime.STATEFUL_SESSION_TYPE );
// or...
// create a StatelessRuleSession
StatelessRuleSession ruleSession =
(StatelessRuleSession) ruleRuntime.createRuleSession(uri,
new HashMap(), RuleRuntime.STATELESS_SESSION_TYPE);
// add input objects...
List input = new ArrayList();
input.add(inputCustomer);
input.add(inputInvoice);
// Execute the rules...
List results = ruleSession.executeRules(input);
// Release the session.
ruleSession.release();
}
catch (NoClassDefFoundError e) {
if (e.getMessage().indexOf("Exception") != -1) {
System.err.println("Error: The Rule Engine Implementation could not be found.");
}
else {
System.err.println("Error: " + e.getMessage());
}
}
catch (Exception e) {
e.printStackTrace();
}
|
|
|
(c) 2006 by Mauro Carniel |
|
|