Skip Headers
Oracle® Fusion Middleware Language Reference Guide for Oracle Business Rules
11g Release 1 (11.1.1.6.2)

Part Number E10227-07
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
PDF · Mobi · ePub

4 Using a RuleSession

This chapter describes how to use a RulesSession object.

The chapter includes the following sections:

4.1 RuleSession Constructor Properties

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

oracle.rules.rl.configLocale

A Locale object for the desired Locale. If not present in the map, the default Locale is used.

Default Value: the JVM default Locale.

oracle.rules.rl.configLogging

Logging is enabled by default (true). If this property is present and the value is false, logging is disabled.

Default Value: true


4.2 RuleSession Methods

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.

4.3 RL to Java Type Conversion

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

java.lang.Integer

int

java.lang.Character

char

java.lang.Byte

byte

java.lang.Short

short

java.lang.Long

long

java.lang.Double

double

java.lang.Float

float

java.lang.Boolean

boolean

Object

Object

int[]

int[]

char[]

char[]

byte[]

byte[]

short[]

short[]

long[]

long[]

double[]

double[]

float[]

float[]

boolean[]

boolean[]

Object[]

Object[]


4.4 Error Handling

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.

4.5 RL Class Reflection

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.

4.6 XML Navigation

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.

4.7 Obtaining Results from a Rule Enabled Program

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

4.7.1 Overview of Results Examples

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.

4.7.2 Using External Resources to Obtain Results

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");

4.8 Debugging an RL Stacktrace

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 nth 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());

4.9 Using RuleSession Pooling

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.

4.9.1 How to Create a RuleSession Pool

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.

4.9.2 How to Use a RuleSession Pool

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.

4.10 Using RuleSession Options

The RL runtime with a RuleSession supports the following options:

4.10.1 Using the CFG_LOGGING System Property

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.

4.10.2 Using the CFG_DECISION_TRACE_LEVEL Option

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".

4.10.3 Using the CFG_DECISION_TRACE_LIMIT Option

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".