JBoss.orgCommunity Documentation
Drools provides an implementation of the Java Rule Engine API (known as JSR94), which allows for support of multiple rule engines from a single API. JSR94 does not deal in anyway with the rule language itself. W3C is working on the Rule Interchange Format (RIF) and the OMG has started to work on a standard based on RuleML , recently Haley Systems has also proposed a rule language standard called RML.
It should be remembered that the JSR94 standard represents the "least common denominator" in features across rule engines - this means there is less functionality in the JSR94 api than in the standard Drools api. So by using JSR94 you are restricting yourself in taking advantage of using the full capabilities of the Drools Rule Engine. It is necessary to expose further functionality, like globals and support for drl, dsl and xml via properties maps due to the very basic feature set of JSR94 - this introduces non portable functionality. Further to this, as JSR94 does not provide a rule language, you are only solving a small fraction of the complexity of switching rule engines with very little gain. So while we support JSR94, for those that insist on using it, we strongly recommend you program against the Drools API.
There are two parts to working with JSR94. The first part is the administrative api that deals with building and register RuleExecutionSets, the second part is runtime session execution of those RuleExecutionSets.
The RuleServiceProviderManager manages the registration and retrieval of RuleServiceProviders. The Drools RuleServiceProvider implementation is automatically registered via a static block when the class is loaded using Class.forName; in much the same way as JDBC drivers.
Example 6.1. Automatic RuleServiceProvider Registration
// RuleServiceProviderImpl is registered to "http://drools.org/" via a static initialization block Class.forName("org.drools.jsr94.rules.RuleServiceProviderImpl"); // Get the rule service provider from the provider manager. RuleServiceProvider ruleServiceProvider = RuleServiceProviderManager.getRuleServiceProvider("http://drools.org/");
The RuleServiceProvider provides access to the RuleRuntime and
RuleAdministration APIs. The RuleAdministration provides an administration
API for the management of RuleExecutionSets, making it possible to
register a RuleExecutionSet that can then be retrieved via the
RuleRuntime.
First you need to create a RuleExecutionSet before it can be registered; RuleAdministrator provides factory methods to return an empty LocalRuleExecutionSetProvider or RuleExecutionSetProvider. The LocalRuleExecutionSetProvider should be used to load a RuleExecutionSets from local sources that are not serializable, like Streams. The RuleExecutionSetProvider can be used to load RuleExecutionSets from serializable sources, like DOM Elements or Packages. Both the "ruleAdministrator.getLocalRuleExecutionSetProvider( null );" and the "ruleAdministrator.getRuleExecutionSetProvider( null );" take null as a parameter, as the properties map for these methods is not currently used.
Example 6.2. Registering a LocalRuleExecutionSet with the RuleAdministration API
// Get the RuleAdministration RuleAdministration ruleAdministrator = ruleServiceProvider.getRuleAdministrator(); LocalRuleExecutionSetProvider ruleExecutionSetProvider = ruleAdministrator.getLocalRuleExecutionSetProvider( null ); // Create a Reader for the drl URL drlUrl = new URL("http://mydomain.org/sources/myrules.drl"); Reader drlReader = new InputStreamReader( drlUrl.openStream() ); // Create the RuleExecutionSet for the drl RuleExecutionSet ruleExecutionSet = ruleExecutionSetProvider.createRuleExecutionSet( drlReader, null );
"ruleExecutionSetProvider.createRuleExecutionSet( reader, null )" in the above example takes a null parameter for the properties map; however it can actually be used to provide configuration for the incoming source. When null is passed the default is used to load the input as a drl. Allowed keys for a map are "source" and "dsl". "source" takes "drl" or "xml" as its value; set "source" to "drl" to load a drl or to "xml" to load an xml source; xml will ignore any "dsl" key/value settings. The "dsl" key can take a Reader or a String (the contents of the dsl) as a value.
Example 6.3. Specifying a DSL when registering a LocalRuleExecutionSet
// Get the RuleAdministration RuleAdministration ruleAdministrator = ruleServiceProvider.getRuleAdministrator(); LocalRuleExecutionSetProvider ruleExecutionSetProvider = ruleAdministrator.getLocalRuleExecutionSetProvider( null ); // Create a Reader for the drl URL drlUrl = new URL("http://mydomain.org/sources/myrules.drl"); Reader drlReader = new InputStreamReader( drlUrl.openStream() ); // Create a Reader for the dsl and a put in the properties map URL dslUrl = new URL("http://mydomain.org/sources/myrules.dsl"); Reader dslReader = new InputStreamReader( dslUrl.openStream() ); Map properties = new HashMap(); properties.put( "source", "drl" ); properties.put( "dsl", dslReader ); // Create the RuleExecutionSet for the drl and dsl RuleExecutionSet ruleExecutionSet = ruleExecutionSetProvider.createRuleExecutionSet( reader, properties );
When registering a RuleExecutionSet you must specify the name, to be used for its retrieval. There is also a field to pass properties, this is currently unused so just pass null.
Example 6.4. Register the RuleExecutionSet
// Register the RuleExecutionSet with the RuleAdministrator String uri = ruleExectionSet.getName(); ruleAdministrator.registerRuleExecutionSet(uri, ruleExecutionSet, null);
The Runtime, obtained from the RuleServiceProvider, is used to create stateful and stateless rule engine sessions.
To create a rule session you must use one of the two RuleRuntime public constants - "RuleRuntime.STATEFUL_SESSION_TYPE" and "RuleRuntime.STATELESS_SESSION_TYPE" along with the uri to the RuleExecutionSet you wish to instantiate a RuleSession for. The properties map can be null, or it can be used to specify globals, as shown in the next section. The createRuleSession(....) method returns a RuleSession instance which must then be cast to StatefulRuleSession or StatelessRuleSession.
Example 6.6. Stateful Rule
(StatefulRuleSession) session = ruleRuntime.createRuleSession( uri, null, RuleRuntime.STATEFUL_SESSION_TYPE ); session.addObject( new PurchaseOrder( "lots of cheese" ) ); session.executeRules();
The StatelessRuleSession has a very simple API; you can only call executeRules(List list) passing a list of objects, and an optional filter, the resulting objects are then returned.
Example 6.7. Stateless
(StatelessRuleSession) session = ruleRuntime.createRuleSession( uri, null, RuleRuntime.STATELESS_SESSION_TYPE ); List list = new ArrayList(); list.add( new PurchaseOrder( "even more cheese" ) ); List results = new ArrayList(); results = session.executeRules( list );
It is possible to support globals with JSR94, in a none portable manner, by using the properties map passed to the RuleSession factory method. Globals must be defined in the drl or xml file first, otherwise an Exception will be thrown. the key represents the identifier declared in the drl or xml and the value is the instance you wish to be used in the execution. In the following example the results are collected in an java.util.List which is used as global:
java.util.List globalList = new java.util.ArrayList( ); java.util.Map map = new java.util.HashMap( ); map.put( "list", globalList ); //Open a stateless Session StatelessRuleSession srs = (StatelessRuleSession) runtime.createRuleSession( "SistersRules", map, RuleRuntime.STATELESS_SESSION_TYPE ); ... // Persons added to List // call executeRules( ) giving a List of Objects as parameter // There are rules which will put Objects in the List // fetch the list from the map List list = (java.util.List) map.get("list");
Do not forget to declare the global "list" in your DRL:
package SistersRules; import org.drools.jsr94.rules.Person; global java.util.List list rule FindSisters when $person1 : Person ( $name1:name ) $person2 : Person ( $name2:name ) eval( $person1.hasSister($person2) ) then list.add($person1.getName() + " and " + $person2.getName() +" are sisters"); assert( $person1.getName() + " and " + $person2.getName() +" are sisters"); end
If you need more information on JSR 94, please refer to the following references
Official JCP Specification for Java Rule Engine API (JSR 94)
The Java Rule Engine API documentation
The Logic From The Bottom Line: An Introduction to The Drools Project. By N. Alex Rupp, published on TheServiceSide.com in 2004
Getting Started With the Java Rule Engine API (JSR 94): Toward Rule-Based Applications. By Dr. Qusay H. Mahmoud, published on Sun Developer Network in 2005
Jess and the javax.rules API. By Ernest Friedman-Hill, published on TheServerSide.com in 2003