The goal of this specification aims to make the client code for simple rule-based applications less dependent on
rule engine vendor-specific classes. The basic interactions with a rule engine are typically parsing the rules in scope
of a rule set, adding object references to one engine, firing the rules and getting results from the engine.
JSR94 defines a rule set as a rule execution set which can be loaded from external resources like URIs, Input
streams, XML streams and readers. A rule execution set is a collection of rules. Another important JSR94 concept is the
rule session which is a runtime connection between a client and a rule engine. A rule session is associated
with a single rule execution set, consumes rule engine resources and must be explicitly released when the client no
longer requires it. Session can be stateless or stateful. Stateless executes a rule execution set with a list of input
objects in one call. Stateful is designed to maintain a long time conversation between the client and the engine and
provides mechanism to assert / retract input object to the session.
The client code may run on server layer like a servlet controller, in a service tier part of an EJB or POJO, or in a
standalone JSE JVM. The javax.rules API divides interaction with rule engines into administrative and runtime
interactions. The basic operations supported by JSR-94 are:
• Acquiring a rule session for a registered rule execution set.
• Deploying and undeploying rulesets into a rule engine instance
• Querying simple metadata about a ruleset
• Executing a ruleset in either a stateful or stateless mode
The client code for run time execution
From the client point of view the interaction with a rule engine is done using the rule session. But the first part is
to get an instance of the rule engine implementation. The service provider manager helps to get a rule service provider
which in turn helps to get rule run time and rule administration implementations. Every specific implementation exposes
an uniquely identifier for the service provider URL.
// Get the rule service provider from the provider manager
Class.forName("ilog.rules.bres.jsr94.IlrRuleServiceProvider");
RuleServiceProvider serviceProvider = RuleServiceProviderManager.getRuleServiceProvider(“ilog.rules.bres.jsr94”);
• For the reference implementation the URL is org.jsp.jsr94.ri.RuleServiceProvider
• For JRules the is ilog.rules.bres.jsr94.IlrRuleServiceProvider, and the service provider name is
ilog.rules.bres.jsr94
• For JBoss-drools the is org.drools.jsr94.rules.RuleServiceProviderImpl and the service provider name is
http://drools.org.
The code above is used for JSE deployment, as in JEE environment runtime clients should resolve the RuleRuntime and
RuleAdministrator services directly using JNDI lookup.
Javax.naming.InitialContext initialContext = new InitialContext();
RuleRuntime ruleRuntime =
(RuleRuntime) PortableRemoveObject.narrow(
initialContext.lookup("org.jcp.jsr94.ri.RuleRuntime"),RuleRuntime.class );
In JSE we can use an inversion of control pattern and get those URL references from a properties file or a file
descriptor.
The next step is to get a rule engine run time.
// Get a RuleRuntime and invoke the rule execution.
RuleRuntime ruleRuntime = serviceProvider.getRuleRuntime();
The RuleRuntime interface exposes the method to create a rule session given a previously registered RuleExecutionSet
URI. It is possible to execute the rule engine in stateless or stateful mode using different type of rule session. We
need to specify the rule execution set URI and the session type.
StatelessRuleSession statelessRuleSession = (StatelessRuleSession) ruleRuntime.createRuleSession(ruleExecutionSetURI,
rulesessionProperties,RuleRuntime.STATELESS_SESSION_TYPE);
The second parameter is optional and is used to add some additional properties to the session. In JRules it is used to
give the references to the rule set parameters and to specify if the RuleSession is a J2SE POJO rule session or a J2EE
POJO rule session:
Map rulesessionProperties = new HashMap(); rulesessionProperties.put("loan", loan);
rulesessionProperties.put("borrower", borrower);
A stateless rules session exposes a stateless rule execution API to an underlying rules engine with two different
methods to call the execution of the rule:
public java.util.List executeRules(java.util.List objects)
throws InvalidRuleSessionException,java.rmi.RemoteException
The list of objects set as parameters will be inserted in the engine's working memory. The list returned includes all
the objects created by the executed rules. The only things we can retrieve with JSR94 from an execution are the objects
in the working memory. The second API uses a filter of objects the client code can supply to select those objects that
should be returned from the rule engine.
Filtering objects
To filter out objects from the list of returned objects from the rule execution call, the client code needs to provide
an implementation of the ObjectFilter interface. The implementing class receives callback methods that allow filtering
out objects as desired. Here is a simple filter class that removes any loan which does not have messages.
public class MyObjectFilter implements ObjectFilter {
@Override
public Object filter(Object obj) {
if (obj instanceof Loan) {
Loan loan = (Loan)obj;
if (loan.getMessages().size() != 0)
return obj;
}
return null;
}
Get rule execution set meta data
RuleRuntime can also being used to get the list of URIs that currently have rule execution set registered with them
using the API List listURIs=ruleRuntime.getRegistrations();
The other object involved is the RuleExecutionSetMetadata interface which exposes metadata about a Rule Execution Set
to runtime clients of a RuleSession like the name, URI and description of the rule execution set.
RuleExecutionSetMetadata metadata=statelessRuleSession
.getRuleExecutionSetMetadata();
metadata.getName();
metadata.getDescription();
metadata.getUri()
Stateful session
Client code can use stateful session to conduct long running conversation with the engine, and control the working
memory with new facts. Input Objects can be progressively added to the StatefulRuleSession through the addObject
method. Output Objects can be progressively retrieved though the getObject method.
StatefulRuleSession statefulRuleSession= (StatefulRuleSession) getRuleRuntime()
.createRuleSession(ruleExecutionSetURI, getProperties(loan, borrower),RuleRuntime.STATEFUL_SESSION_TYPE);
//first call the normal execution
statefulRuleSession.executeRules();
Loan l2 = new Loan(250000,240,7.25);
Handle hdl=statefulRuleSession.addObject(l2);
statefulRuleSession.executeRules();
Objects that have been added to the StatefulRuleSession must be removed and updated using the removeObject and
updateObject methods. A client must test for the existence of an added Object using the containsObject method. The
removeObject, updateObject, and containsObject methods must all use a javax.rules.Handle implementation instances
to refer to and identify Object instances. Handle are used to ensure that Object instances can be unambiguously
identified in the event of multiple class loaders being used or the StatefulRuleSession being serialized. The addObject
methods returns a Handle instance for an Object added to a StatefulRuleSession, so that it can be used in the remove
API for example.
In JRules Ruleset parameters and objects added to the RuleSession when it is created are uniquely identified by an
instance of the IlrRuleSessionHandle class.
Administrate rule execution set
Administrative tasks supported by the API javax.rules.admin include instantiating the rule engine and loading rules. To
get the rule administrator we use the service provider such as: RuleAdministrator ruleAdministrator =
serviceProvider.getRuleAdministrator();
The RuleAdministrator allows RuleExecutionSet instances to be registered against a URI for use from the runtime API, as
well as methods to retrieve a RuleExecutionSetProvider and a LocalRuleExecutionSetProvider implementation. The
RuleExecutionSetProvider interface defines methods to create a RuleExecutionSet from a number of Serializable sources
LocalRuleExecutionSetProvider ruleExecutionSetProvider =
ruleAdministrator.getLocalRuleExecutionSetProvider(null);
RuleExecutionSet ruleSet = ruleExecutionSetProvider.createRuleExecutionSet( inputStream, null );
ruleAdministrator.registerRuleExecutionSet( ruleSet.getName(),ruleSet,null );
The local rule execution set provider sends a local execution set to a remote engine using serialization and
marshaling. The API get(Local)RuleExecutionSetProvider takes an argument of type Map, which is documented as
"additional properties" and used for setting the JNDI properties. The source for the rule can come from
non-Serializable resources, such as binary InputStreams or character-based Readers. Registering the execution set to a
URI helps to create session to an execution set. The rules registered using the rules admin API are the only rules
accessible to the runtime clients.
The following code gets the name and description of the execution set deployed:
ruleSet.getDescription();
ruleSet.getName();
getName() in the case of JRules Rule Execution server deployment returns the rule set path. From the rules set we can
get all the rules in a list and then for each rule its name and description.
Rule.getName()returns in the case of JRules a string which specify the language name and the name space for this rule,
like for example “IRL/validation/maximum_amount-brl.irl”. The rule.getDescription() returns the rule in the language of
the rule engine vendor. For JRules it is the Ilog rule language such as:
package validation {
rule maximum_amount {
property status = "new";
when {
miniloan.Loan() from loan;
evaluate (loan.amount > 1000000);
} then {
loan.addToMessages("The loan cannot exceed
1,000,000");
loan.reject();
}
}
}
|