Oracle® Fusion Middleware Language Reference Guide for Oracle Business Rules 11g Release 1 (11.1.1.6.1) Part Number E10227-06 |
|
|
PDF · Mobi · ePub |
This chapter describes how to use a RulesSession object.
The chapter includes the following sections:
This section shows you the steps for creating a rule enabled application and describes using a RuleSession
object. The package oracle.rules.rl contains the RuleSession
object.
The RuleSession
no argument constructor returns a RuleSession
with the default locale and logging options set.
Table 4-1 shows the RuleSession
constructor properties.
Table 4-1 RuleSession Properties
Property Name | Property Value |
---|---|
|
A Locale object for the desired Locale. If not present in the map, the default Locale is used. Default Value: the JVM default Locale. |
|
Logging is enabled by default ( Default Value: |
The outputWriter
property determines where println
, watch
, and show
output goes.
The rulesetName property sets the ruleset when RL statements are executed without an explicit named ruleset. The default rulesetName is main
.
The executeRuleset methods parse and execute the given ruleset text (given as a String or a java.io.Reader).
The callFunction method invokes the named RL function (which must either be a built-in RL function or must have been previously defined with no parameters using one of the executeRuleset methods) and returns its result. Functions with a single argument can be invoked with the callFunctionWithArgument method. Functions taking any number of arguments can be called using the callFunctionWithArgumentList
or callFunctionWithArgumentArray
methods. The argument List or array must contain a Java Object for each RL function parameter.
Table 4-2 describes how Java Object types are be converted to RL types for passing arguments to RL functions, and conversely how RL types are converted to Java types for passing the RL function return value to Java.
Table 4-2 RL to Java Object Conversion
Java Class | RL Type |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RuleSession method invocations that throw a ParseException
or TypeCheckException
do not affect the state of the RuleSession. A Java application, for example, an interactive command-line, can catch these exceptions and continue using the RuleSession.
RuleSession method invocations that throw a RLRuntimeException
may have affected the state of the RuleSession and the RuleSession may not be in a usable state for the application to proceed. Robust applications should attempt to catch and recover from RLRuntimeExceptions
in RL at a point near where the exception is thrown.
Other exceptions likely indicate a serious problem that the application cannot handle.
You can use an RL class like a Java class in an RL program. The new
, instanceof
, and cast
operators work on both kinds of class. However, when an instance of an RL class is passed to a Java program, it is actually an instance of oracle.rules.rl.RLObject
. A Java program can use the following classes: RLClass
, RLProperty
, and RLArray
to examine the RLObject
in a manner similar to using the java.lang.Class
, java.lang.reflect.Field
, and java.lang.Array
classes to reflect a java.lang.Object
. The package oracle.rules.rl
contains RLCLass
, RLProperty
, and RLArray
.
XLink objects are created and asserted as facts by the assertTree function. An RL rule can use XLinks to reason about the hierarchy of elements asserted by assertTree.
When you create a a rule enabled program with Oracle Business Rules, a common question is, "How do I get the results of the evaluation?"
This section one approaches to extracting or exposing results of rule evaluation from the rule engine.
This section covers the following:
See Also:
"Working with Rules SDK Decision Point API" in the Oracle Business Rules User's Guide
The examples in this section show a highway incident notification system. These examples show the different approaches to access the results of rule engine evaluation. The examples use two Java classes: traffic.TrafficIncident
and traffic.IncidentSubscription
.
Note:
The traffic.*
sample classes are not included in the Oracle Business Rules distribution.
The TrafficIncident
class represents information about an incident affecting traffic and contains the following properties:
Which highway
Which direction
Type of incident
Time incident occurred
Estimated delay in minutes
The IncidentSubscription
class describes a subscription to notifications for incidents on a particular highway and contains the following properties:
Subscriber - the name of the subscriber
The highway
The direction
In the example using these classes, when an incident occurs that affects traffic on a highway, a TrafficIncident
object is asserted and rule evaluation determines to whom notifications are sent.
In the examples, the sess
object is a RuleSession
and a number of incident subscriptions are asserted. As a simplification, it is assumed that the TrafficIncident
objects are short lived. They are effectively an event that gets asserted and only those subscribers registered at that time are notified.
The classes in these examples are all Java classes. However, it is possible to manipulate instances of RL classes in Java using the RL class reflection.
See Also:
For documentation see the Javadoc for the RLClass, RLObject, RLProperty and RLArray classes in the oracle.rules.rl
package. Thus, RL objects, or instances of RL classes, can be used to hold rule engine results as well as Java objects.
This approach is similar to asserting a container for results, except that instead of a container, the object is a means to affecting resources external to the rules engine. For example, this could involve queuing up or scheduling work to be done, updating a database, sending a message. Any Java method accessible in the action may be invoked to effect the results. As with the container use case, the objects used in this example to access the external resources are not re-asserted since their content is not being reasoned on.
Example 4-1 shows the IncidentDispatcher
object that is asserted and then used to dispatch the notification.
Example 4-1 Obtaining Results Using External Resources
rule incidentAlert { if (fact TrafficIncident ti && fact IncidentSubscription s && s.highway == ti.highway && s.direction == ti.direction && fact IncidentDispatcher dispatcher) { dispatcher.dispatch(s.subscriber, ti); } }
Example 4-2 shows Java code that asserts an IncidentDispatcher
and a TrafficIncident
, and then invokes the rule engine. This could also be accomplished using an object that is being reasoned on, but this would require a test in the rule condition to avoid an infinite loop of rule firing.
Example 4-2 Sample Showing Results with External Resources
sess.callFunctionWithArgument("assert", new IncidentDispatcher()); // An accident has happened TrafficIncident ti = new TrafficIncident(); ti.setHighway("I5"); ti.setDirection("south"); ti.setIncident("accident"); ti.setWhen(new GregorianCalendar(2005, 1, 25, 5, 4)); ti.setDelay(45); sess.callFunctionWithArgument("assert", ti); sess.callFunction("run");
The runtime provides detailed debugging information in an RL stacktrace. When possible, if there is an error, the runtime provides extra context that helps identify the location of a problem. This extra context is useful when working with Rules SDK and Rules Designer.
The stacktrace includes the extra context showing the information for rule conditions, rule actions, functions, variables, and RL class definitions. The XPath style format consists of an RL construct and, if named, followed by the name enclosed in parentheses. If a number, n
, appears in brackets after a construct it indicates the n
th item following the previous construct. In combination with Rules SDK, RL generation should significantly assist in identifying a location for an error in Rules Designer.
For example, consider the ruleset shown in Example 4-3. When this ruleset executes, it gives the following report:
RLNullPointerException: object cannot be null at line 12 column 13 in stackTraceContext /Rule(porsche)/Pattern(car)/Test[1] at line 17 column 5 in stackTraceContext
Example 4-3 Test Ruleset
ruleset stackTraceContext { class Car { String make; String model; } rule porsche { if (fact Car car && car.make.startsWith("Porsche")) { println(car.make + " " + car.model); } } assert(new Car()); }
ruleset stackTraceContext
{
class Car
{
String make;
String model;
}
rule porsche
{
if (fact Car car &&
car.make.startsWith("Porsche"))
{
println(car.make + " " + car.model);
}
}
assert(new Car());
A typical application that uses rules evaluates the same rules multiple times, with different facts corresponding to separate requests. Initializing a RuleSession typically takes a few seconds depending on the number of rules involved. In contrast, the time to execute the rules is typically much less. Therefore, better performance can be achieved by initializing a RuleSession one time and reusing it for each new request. Using RuleSession pooling, you can create a pool of RuleSession instances that supports improved performance and scalability of applications that use rules.
In order for performance to scale up with increasing load, more than one RuleSession is required. A pool of RuleSession instances supports improved performance and scalability of applications that use rules. A pool is instantiated with a list of the RL code that is used to initialize each RuleSession created by the pool. The RL code is executed in the order in which it appears in the list. The number of RuleSession instances to create initially may be specified. In general, this should be a small value and usually the default should be sufficient.
Typically, the RL code is generated from a RuleDictionary created with the Rules SDK. Example 4-4 demonstrates creating and using a RuleSessionPool with RL code from a RuleDictionary.
Example 4-4 Creating a RuleSession Pool
RuleDictionary rd; // Code to load rule dictionary not shown List rlList = new ArrayList(); rlList.add(rd.dataModelRL()); List rulesetAliases = rd.getRuleSetAliases(true); for (String alias : rulesetAliases) { rlList.add(rd.ruleSetRL(alias)); } RuleSessionPool pool = new RuleSessionPool(rlList);
If the rules in use by an application are updated, the application may need to load the new rules so that subsequent rule executions use the new rules. This is supported by the pool by invoking the refreshPool method passing it a list of the new RL. After the pool has been refreshed, RuleSessions returned by getPoolableRuleSession will have been initialized with the new RL code. When RuleSessions that were obtained before the refresh are returned using returnPoolableRuleSession, they are not placed back in the pool. The refreshed pool will only contain RuleSessions initialized with the new RL code.
To execute rules using a RuleSession, you obtain a RuleSession from the pool and then return it after execution is complete. A poolable RuleSession is acquired by invoking the getPoolableRuleSession method. The pool creates new RuleSessions as required. An invocation of getPoolableRuleSession will not block waiting for a free RuleSession.
When rule execution has been completed, the poolable RuleSession is returned to the pool by invoking the returnPoolableRuleSession method. When a RuleSession is returned to the pool it is reset by the pool by invoking the built-in RL function, reset(). This removes all facts from working memory to prepare the RuleSession for the next execution. Every RuleSession that is retrieved from the pool should be returned to the pool. If an error has occurred during rule execution that results in the RuleSession being unfit for further use, the pool detects this and discards it.
Besides clearing working memory, the reset() function re-executes the initializers of all non-final global variables. The initializer of a non-final global variable can be used to perform other initialization at reset if this is required.
Example 4-5 demonstrates using a RuleSession from the pool.
Example 4-5 Using a Rule Session Pool
PoolableObject po = pool.getPoolableRuleSession(); RuleSession engine = po.getPooledObject(); // use the RuleSession to execute rules as required here pool.returnPoolableRuleSession(po);
A soft upper bound on the size of the pool can be specified. This allows the pool to respond to temporary increases in demand by growing the pool while allowing the pool to shrink down to this soft upper bound when demand subsides.
Using the RuleSession pooling implementation, you create RuleSession instances when the getPoolableRuleSession method is invoked and the pool is empty. If the load is heavy enough, this will result in an instance count that is greater than the soft limit.
As the load subsides, the number of RuleSesion instances in the pool will automatically be decreased to the soft limit.
The RL runtime with a RuleSession supports the following options:
RuleSession.CFG_LOGGING
.
RuleSession.CFG_DECISION_TRACE_LEVEL
RuleSession.CFG_DECISION_TRACE_LIMIT
RL Language runtime looks for CFG_LOGGING
as a system property as well as a Boolean in the config Map passed to the RuleSession constructor. A value in the Map overrides the system property value.
You can configure the trace level in a RuleSession or in a RuleSessionPool by including the RuleSession.CFG_DECISION_TRACE_LEVEL
initialization parameter and specifying a level in the configuration Map passed to the RuleSession or RuleSessionPool constructor. This sets the decision trace level at the time a RuleSession is created; invoking reset()
guarantees that the level after the reset()
is returned to the configured value, in case it had been changed during rule execution. For more information, see Section 1.7.2, "Using Rule Engine Level Decision Tracing".
The size of a trace is limited by limiting the number of entries in a decision trace. This necessary to avoid infinite rule fire loops, due to a possible bug in the rules, from creating a trace that consumes all available heap in the JVM. Set the trace limit with the setDecisionTraceLimit function. The limit may also be configured in a RuleSession (or RuleSessionPool) by including the RuleSession.CFG_DECISION_TRACE_LIMIT
initialization parameter with the desired limit in the configuration Map passed to the RuleSession or RuleSessionPool constructor. For more information, see Section 1.7.2, "Using Rule Engine Level Decision Tracing".