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 propties 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 propperties 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