7 Working with Rules SDK Decision Point API

This chapter describes how to use Oracle Business Rules SDK (Rules SDK) to write applications that access, create, modify, and execute rules in Oracle Business Rules dictionaries (and work with the contents of a dictionary). It also provides a brief description of Rules SDK and shows how to work with the Rules SDK Decision Point API.

The chapter includes the following sections:

For more information, see Oracle Fusion Middleware Java API Reference for Oracle Business Rules.

7.1 Introduction to Rules SDK and the Car Rental Sample Application

The Rules SDK consists of four areas:

  • Engine: provides for rules execution

  • Storage: provides access to rule dictionaries and repositories

  • Editing: provides a programatic way to create and modify dictionary components

  • Decision Point: provides an interface to access a dictionary and execute a decision function

Other than for explanation purposes, there is not an explicit distinction between these areas in Rules SDK. For example, to edit rules you also need to use the storage area of Rules SDK to access a dictionary. These parts of the Rules SDK are divided to help describe the different modes of usage, rather than to describe distinct Rules SDK APIs.

7.1.1 Introduction to Decision Point API

The Decision Point API provides a concise way to execute rules. Most users create Oracle Business Rules artifacts, including data model elements, rules, Decision Tables, and rulesets using the Rules Designer extension to Oracle JDeveloper. Thus, most users do not need to work directly with the engine, storage, or editing parts of Rules SDK.

To work with the Rules SDK Decision Point package you need to understand three important classes:

  • DecisionPoint: is a helper class that follows the factory design pattern to create instances of DecisionPointInstance. In most applications there should be one DecisionPoint object that is shared by all application threads. A caller uses the getInstance() method of DecisionPoint to get an instance of DecisionPointInstance which can be used to call the defined Decision Point.

  • DecisionPointBuilder: follows the Builder design pattern to construct a Decision Point.

  • DecisionPointInstance: users call invoke() in this class to assert facts and execute a decision function.

The DecisionPoint classes support a fluent interface model so that methods can be chained together. For more information, see

http://www.martinfowler.com/bliki/FluentInterface.html

A Decision Point manages several aspects of rule execution, including:

  • Use of oracle.rules.rl.RuleSession objects

  • Reloading of a dictionary when the dictionary is updated

To create a Decision Point in a Java application you need the following:

  • Either the name of a dictionary to be loaded from an MDS repository or a pre-loaded oracle.rules.sdk2.dictionary.RuleDictionary instance.

  • The name of a decision function stored in the specified dictionary.

7.1.2 How to Obtain the Car Rental Sample Application

This chapter shows a car rental application that demonstrates the use of Rules SDK and the Decision Point API. You can obtain the sample application in a ZIP file, CarRentalApplication.zip. This ZIP contains a complete JDeveloper application and project.

The source code for Oracle Business Rules-specific samples and SOA samples are available online in the Oracle SOA Suite samples page.

To work with the sample unzip CarRentalApplication.zip into an appropriate directory. The car rental application project contains a rules dictionary and several Java examples using Rules SDK.

7.1.3 How to Open the Car Rental Sample Application and Project

The Car Rental sample application shows you how to work with the Rules SDK Decision Point API.

To open the car rental sample application:

  1. Start Oracle JDeveloper.

  2. Open the car rental application in the directory where you unzipped the sample. For example, from the File menu select Open... and in the Open dialog navigate to the CarRentalApplication folder.

  3. In the Open dialog select CarRentalApplication.jws and click Open.

  4. In the Application Navigator, expand the CarRentalApplication, expand Application Sources and Resources. This displays the Oracle Business Rules dictionary named CarRental.rules and several Java source files.

7.2 Creating a Dictionary for Use with a Decision Point

The car rental sample uses the Rules SDK Decision Point API with either a pre-loaded Oracle Business Rules dictionary or a repository stored in MDS. When you are working in a development environment you can use the Decision Point API with the pre-loaded dictionary signature. In a production environment you would typically use a Decision Point with the MDS repository signature.

The CarRental dictionary is pre-defined and is available in the car rental sample application.

To work with the Decision Point API you need to create a dictionary that contains a decision function (the car rental sample application comes with a predefined dictionary and decision function).

You perform the following steps to create a dictionary and a decision function:

7.2.1 How to Create Data Model Elements for Use with a Decision Point

You need the following to add to a decision function when you create an application with a Decision Point.

To view the data model in the supplied car rental sample application:

  1. In Rules Designer, click the Facts navigation tab.

  2. Select the Java Facts tab, as shown in Figure 7-1.

    The Java Facts tab shows four fact types imported, in addition to the fact types provided as built-in to the dictionary.

    The Driver Java Fact is imported from the Driver Java class in the project.

    The Denial Java Fact is imported from Denial Java class in the project.

    The LicenseType and VehicleType facts are imported from the nested enum classes defined in the Driver class.

    Figure 7-1 Defined Java Facts for the Car Rental Sample Application

    Description of Figure 7-1 follows
    Description of "Figure 7-1 Defined Java Facts for the Car Rental Sample Application"

When you use a Decision Point with Rules SDK, you call a decision function in a specified dictionary. The decision function that you call can contain one or more rulesets that are executed as part of the Decision Point.

To view the ruleset in the supplied car rental sample application:

  1. In Rules Designer, expand the CarRentalApplication.

  2. In the CarRentalApplication, expand Resources.

  3. Double-click the CarRental.rules.

7.2.2 How to View a Decision Function to Call from the Decision Point

When you work with the Decision Point API you use decision functions to expose an Oracle Business Rules dictionary. For more information on decision functions, see Chapter 6, "Working with Decision Functions".

To view the decision function in the car rental sample application:

  1. In Rules Designer, click the Decision Functions navigation tab. This displays the available decision functions in the CarRental dictionary, as shown in Figure 7-2.

    Figure 7-2 Car Rental Sample Decision Function

    Description of Figure 7-2 follows
    Description of "Figure 7-2 Car Rental Sample Decision Function"

  2. Select the row with CarRentalDecisionFunction and double-click the decision function icon. This opens the Edit Decision Function dialog as shown in Figure 7-3.

    The decision function Inputs table includes a single argument for a Driver fact type.

    The decision function Outputs table includes a single argument for a Denial fact type.

    The decision function Rulesets and Decision Functions area shows Denial Rules:if-then in the Selected box.

    Figure 7-3 Car Rental Decision Function for the Car Rental Sample Application

    Description of Figure 7-3 follows
    Description of "Figure 7-3 Car Rental Decision Function for the Car Rental Sample Application"

7.2.3 How to Create Rules or Decision Tables for the Decision Function

The car rental sample includes two rulesets, one with IF/THEN rules and another containing a Decision Table. You can use either IF/THEN rules or Decision Tables or both in your application if you are using a Decision Point.

To view the rules in the car rental sample application:

  1. In Rules Designer click the Denial Rules:if-then ruleset, as shown in Figure 7-4.

    Figure 7-4 Ruleset with IF/THEN Rules for the Car Rental Sample Application

    Description of Figure 7-4 follows
    Description of "Figure 7-4 Ruleset with IF/THEN Rules for the Car Rental Sample Application"

The Denial Rules:if-then ruleset includes two rules:

  • under age: this rule defines the minimum age of the driver. The rule compares the Driver instance age property to the global Minimum driver age. If the driver is under this age, then a new Denial fact is asserted. A call to the decision function collects this Denial fact, as defined in its output. The rule also calls a user-defined function, audit, to provide some auditing output about why the Denial is created.

  • too many accidents: this rule defines an upper threshold for the number of accidents a driver can have before a rental for the driver is denied. The rule also calls a user-defined function, audit, to provide some auditing output about why the Denial is created.

To view the Decision Table in the car rental application:

  1. In Rules Designer, click the Denial Rules:decision table ruleset, as shown in Figure 7-5.

Figure 7-5 Ruleset with Decision Table for the Car Rental Sample Application

Description of Figure 7-5 follows
Description of "Figure 7-5 Ruleset with Decision Table for the Car Rental Sample Application"

7.2.4 What You Need to Know About Using Car Rental Sample with a Decision Table

The car rental sample application includes the Denial Rules: decision table ruleset. To switch to use a Decision Table in the supplied decision function sample, move the Denial Rules:if-then from the Selected area in the decision function and add the Denial Rules: decision table ruleset, which uses a Decision Table to define similar rules, as shown in Figure 7-6.

Figure 7-6 Decision Function for Car Rental Sample with Decision Table Ruleset

Description of Figure 7-6 follows
Description of "Figure 7-6 Decision Function for Car Rental Sample with Decision Table Ruleset"

7.3 Creating a Java Application Using Rules SDK Decision Point

When use Rules SDK in a development environment you of the option of using Decision Point API with a pre-loaded dictionary. In a production environment you typically use the Decision Point API with the MDS repository signature and the dictionary is stored in MDS. For more information on using a Decision Point with, see Section 7.5, "What You Need to Know About Using Decision Point in a Production Environment".

The source code for Oracle Business Rules-specific samples and SOA samples are available online in the Oracle SOA Suite samples page.

The CarRentalProject project includes the com.example.rules.demo package that includes the car rental sample file, CarRentalWithDecisionPointUsingPreloadedDictionary.java. The project also includes several .java source files that support different variations for using Decision Point. Table 7-1 provides a summary of the different versions of the car rental sample.

For more information on working with the Rules SDK Decision Point API, see Oracle Fusion Middleware Java API Reference for Oracle Business Rules.

Table 7-1 Java Files in the Decision Point Sample CarRentalProject

Base Java Filename Description

CarRental

This is the base class for all of the examples. It contains constant values for using the CarRental dictionary and a method createDrivers which creates instances of the Driver class.

CarRentalWithDecisionPoint

Contains a static attribute of type DecisionPoint and a method checkDriver() that invokes a Decision Point with a specified instance of the Driver class. This class includes these methods for the sample application so that both the MDS repository and pre-loaded dictionary examples can share the same checkDriver() implementation.

CarRentalWithDecisionPointUsingMdsRepository

Contains an example of creating a Decision Point that uses MDS to access and load the rule dictionary. In a production environment, most applications use the Decision Point API with MDS.

CarRentalWithDecisionPointUsingPreloadedDictionary

Contains an example of creating a Decision Point from an instance of the RuleDictionary class. This example also contains code for manually loading the dictionary to create a RuleDictionary instance.

CarRentalWithRuleSession

Contains an advanced usage of the Engine API that is documented further in the comments.

CarRentalWithRuleSessionPool

Contains an advanced usage of the Engine API that is documented further in the comments.

Denial

Contains the class that defines the Denial fact type used to create the rules and Decision Table.

Driver

Contains the class that defines the Driver fact type used to create the rules and Decision Table.

DriverCheckerRunnable

Contains the class which can be used as a thread for simulating concurrent users invoking the Decision Point.


7.3.1 How to Add a Decision Point Using Decision Point Builder

To use a Decision Point you create a DecisionPoint instance using DecisionPointBuilder, as shown in Example 7-1.

Example 7-1 Using the Decision Point Builder

    static {
        try {
            // specifying the Decision Function and a pre-loaded
            // RuleDictionary instance 
            m_decisionPoint =  new DecisionPointBuilder()
                                .with(DF_NAME)
                                .with(loadRuleDictionary())
                                .build();
        } catch (SDKException e) {
            System.err.println("Failed to build Decision Point: " + e.getMessage());
            e.printStackTrace();
        }
    }

Example 7-1 shows the DecisionPointBuilder supports a fluent interface pattern, so all methods can easily be chained together when you create a Decision Point. The three most common methods for configuring the Decision Point with DecisionPointBuilder are overloaded to have the name with(). Each with() method takes a single argument of type RuleDictionary, DictionaryFQN, or String. The DecisionPointBuilder also supports similar set and get methods: getDecisionFunction(), setDecisionFunction(), getDictionary(), setDictionary(), getDictionaryFQN(), setDictionaryFQN().

This chain shown in Example 7-1 includes the following steps:

  1. The first step is to create a DecisionPointBuilder instance with code such as the following:

    new DecisionPointBuilder()
    
  2. The with() method using a String argument defines the name of the decision function that the Decision Point executes. Calling this method is mandatory.

    .with(DF_NAME)
    

    The DF_NAME specifies the name of the decision function you define for your application. For example for the sample car rental application DF_NAME is defined in CarRental.java as CarRentalDecisionFunction.

  3. Call only one of the other two with() methods. In this case the sample code uses a pre-loaded Rule Dictionary instance, containing the specified decision function. The loadDictionary() method loads an instance of RuleDictionary from a file. Example 7-2 shows the loadDictionary() method. For more information, see Section 7.3.2, "How to Use a Decision Point with a Pre-loaded Dictionary".

    .with(loadRuleDictionary())
    
  4. Call the build() method to construct and return a DecisionPoint instance.

The DecisionPoint instance is shared among all instances of the application, which is why it is a static attribute and created in a static block. Another way of initializing the DecisionPoint would be to initialize the m_decisionPoint attribute with a static method that created and returned a DecisionPoint instance.

7.3.2 How to Use a Decision Point with a Pre-loaded Dictionary

Example 7-2 shows the loadRuleDictionary() method that loads an instance of RuleDictionary from a file.

When reading or writing a dictionary directly from a file as shown in Example 7-2, ensure to set the encoding to UTF-8. If this is not done, Unicode characters used in the dictionary are corrupted. The UTF-8 option must be set explicitly in the FileInputStream or OutputStreamWriter constructor. Do not use Java classes such as FileReader and FileWriter, as these classes always use the platform default encoding which is usually an ASCII variant rather than a Unicode variant.

Example 7-2 Load Rule Dictionary Method

private static RuleDictionary loadRuleDictionary(){ 
        RuleDictionary dict = null; 
        BufferedReader reader = null; 
        try { 
            reader = new BufferedReader( 
                        new InputStreamReader( 
                            new FileInputStream( 
                                new File(DICT_LOCATION)), "UTF-8")); 
            dict = RuleDictionary.readDictionary(reader, 
                                                 new 
DecisionPointDictionaryFinder(null)); 
 
            List<SDKWarning> warnings = new ArrayList<SDKWarning>(); 
 
            dict.update(warnings); 
            if (warnings.size() > 0) { 
                System.err.println("Validation warnings: " + warnings); 
            } 
        } catch (SDKException e){ 
            System.err.println(e); 
        } catch (FileNotFoundException e){ 
            System.err.println(e); 
        } catch (IOException e){ 
            System.err.println(e); 
        } finally { 
            if (reader != null) { try { reader.close(); } catch (IOException 
ioe) {ioe.printStackTrace();}} 
        } 
        return dict; 
    } 

7.3.3 How to Use Executor Service to Run Threads with Decision Point

The car rental sample allows you to use Oracle Business Rules and simulate multiple concurrent users. Example 7-3 shows use of the Java ExecutorService interface to execute multiple threads that invoke the Decision Point. The ExecutorService is not part of the Rules SDK Decision Point API.

Example 7-3 Checking Drivers with Threads that Invoke Decision Point

        ExecutorService exec = Executors.newCachedThreadPool();
        List<Driver> drivers = createDrivers();
 
        for (int i = 0; i < NUM_CONCURRENT; i++) {
            Driver driver = drivers.get(i % drivers.size());
            exec.execute(new DriverCheckerRunnable(driver));
        }

Example 7-3 includes the following code for the sample application:

  • Create the Executor Service:

    ExecutorService exec = Executors.newCachedThreadPool();
    
  • Call method createDrivers(), defined in CarRental.java, to create a list of Driver instances.

    List<Driver> drivers = createDrivers();
    
  • A loop through a list of Driver instances to fill the driver list with drivers.

  • A loop to start multiple threads from DriverCheckerRunnable instances. These instances open a Decision Point and run the rules on each driver. For information on this code, see Section 7.3.4, "How to Create and Use Decision Point Instances".

Example 7-4 shows the code that waits for the threads to complete.

Example 7-4 Code to Await Thread Termination

        try {
            exec.awaitTermination(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        exec.shutdown();
    }

7.3.4 How to Create and Use Decision Point Instances

The DriverCheckerRunnable instances call the checkDriver() method. Example 7-5 shows the checkDriver() method that is defined in CarRentalWithDecisionPoint. The checkDriver() method handles invoking Decision Point with a Driver instance.

Example 7-5 Code to Create a Decision Point Instance with getInstance()

public class CarRentalWithDecisionPoint extends CarRental {
 
    protected static DecisionPoint m_decisionPoint;
    
    public static void checkDriver(final Driver driver) {
        try {
            DecisionPointInstance instance = m_decisionPoint.getInstance();
            instance.setInputs(new ArrayList<Object>() {
                    {
                        add(driver);
                    }
                });
            List<Object> outputs = instance.invoke();
 
            if (outputs.isEmpty())
                System.err.println("Oops, no results");
 
            java.util.List<Denial> denials =
                (java.util.List<Denial>)outputs.get(0);
            if (denials.isEmpty()) {
                System.out.println("Rental is allowed for " +
                                   driver.getName());
            } else {
                for (Denial denial : denials) {
                    System.out.println("Rental is denied for " +
                                       denial.getDriver().getName() +
                                       " because " + denial.getReason());
                }
            }
        } catch (RLException e) {
            e.printStackTrace();
        } catch (SDKException e) {
            e.printStackTrace();
        }
    }
    
}

Example 7-5 shows the following:

  • Getting a DecisionPointInstance from the static DecisionPoint defined with the DecisionPointBuilder, with the following code.

     DecisionPointInstance instance = m_decisionPoint.getInstance();
    
  • Add inputs according to the signature of the decision function associated with the Decision Point. This defines one argument of type List as the input. This List contains the Driver instances:

                instance.setInputs(new ArrayList<Object>() {
                        {
                            add(driver);
                        }
                    });
    
  • Invoke the Decision Point and store the return value. The return type follows the same pattern as the decision function which is being called in the Decision Point.

     List<Object> outputs = instance.invoke();
    

    In this case the invoke() returns a List of length one, containing a List of Denial instances.

  • If the return is a List of any other size than one, then this is an error:

    if (outputs.isEmpty())
      System.err.println("Oops, no results");
    
  • The first entry that is returned from the Decision Point is caste it to a List of type List<Denial>:

                java.util.List<Denial> denials =
                    (java.util.List<Denial>)outputs.get(0);
    
  • If the denials list is empty, then no Denial instances were asserted by the rules. This indicates that it is OK to rent a car to the driver. Otherwise, print the reasons why the driver rental was rejected:

                if (denials.isEmpty()) {
                    System.out.println("Rental is allowed for " +
                                       driver.getName());
                } else {
                    for (Denial denial : denials) {
                        System.out.println("Rental is denied for " +
                                           denial.getDriver().getName() +
                                           " because " + denial.getReason());
                    }
                }
    

7.4 Running the Car Rental Sample

In the car rental sample installed on your system, for the code shown in Example 7-2, modify the value of DICT_LOCATION to match the location of the dictionary on your system.

To run the car rental sample on your system:

  1. In the Application Navigator, select the dictionary and from the Edit menu select Copy Path.

  2. In the CarRental.java file, paste the path value into the DICT_LOCATION value.

  3. In the CarRentalProject select the CarRentalWithDecisionPointUsingPreloadedDictionary.java file.

  4. Right-click and in the list select Run.

Example 7-6 shows sample output.

Example 7-6 Output from Car Rental Sample

Rental is allowed for Carol
Rental is allowed for Alice
Rental is allowed for Alice
Rental is allowed for Carol
Rental is denied for Bob because under age, age was 15, minimum age is 21
Mar 13, 2009 11:18:00 AM oracle.rules.rl.exceptions.LogWriter flush
INFO: Fired: under age because driver age less than minimum threshold for license number d222
Mar 13, 2009 11:18:00 AM oracle.rules.rl.exceptions.LogWriter flush
INFO: Fired: under age because driver age less than minimum threshold for license number d222
Rental is denied for Bob because under age, age was 15, minimum age is 21
Rental is allowed for Alice
Rental is allowed for Eve

7.5 What You Need to Know About Using Decision Point in a Production Environment

In a production environment you can use an MDS repository to store Oracle Business Rules dictionaries. When you use an MDS repository to store the dictionary, the steps shown in Section 7.3.1, "How to Add a Decision Point Using Decision Point Builder" and Section 7.3.2, "How to Use a Decision Point with a Pre-loaded Dictionary" change to access the dictionary. The CarRentalWithDecisionPointUsingMdsRepository shows sample code for using Decision Point with MDS.

To see a complete example with deployment steps showing the use of a Decision Point to access a dictionary in MDS, see Section 9.4, "Adding a Servlet with Rules SDK Calls for Grades Sample Application".

Example 7-7 shows the use of DictionaryFQN with DecisionPointBuilder to access a dictionary in an MDS repository. The complete example is shown in the sample code in CarRentalWithDecisionPointUsingMdsRepository.

Example 7-7 Using Decision Point Builder with MDS Repository

    static {
        try {
            // specifying the Decision Function and Dictionary FQN
            // loads the rules from the MDS repository.
            m_decisionPoint = new DecisionPointBuilder()
                                .with(DF_NAME)
                                .with(DICT_FQN)
                                .build();
        } catch (SDKException e) {
            System.err.println("Failed to build Decision Point: " +
                               e.getMessage());

Similar to the steps in Example 7-1, Example 7-7 shows the following:

  1. The first step is to create a DecisionPointBuilder instance with.

    new DecisionPointBuilder()
    
  2. The with() method using a String argument defines the name of the decision function that the Decision Point executes. Calling this method is mandatory.

    .with(DF_NAME)
    

    The DF_NAME specifies the name of the decision function you define for your application. For example for the car rental application this is defined in CarRental.java a CarRentalDecisionFunction.

  3. Call only one of the other two with() methods. In this case the sample code calls a DictionaryFQN to access an MDS repository. Example 7-8 shows the routing that uses the dictionary package and the dictionary name to create the DictionaryFQN.

    .with(DICT_FQN)
    
  4. Call the build() method to construct and return a DecisionPoint instance.

Example 7-8 Using the DictionaryFQN Method with MDS Repository

    protected static final String DICT_PKG = "com.example.rules.demo";
    protected static final String DICT_NAME = "CarRental";
    
    protected static final DictionaryFQN DICT_FQN =
        new DictionaryFQN(DICT_PKG, DICT_NAME);
    protected static final String DF_NAME = "CarRentalDecisionFunction";

7.6 What You Need to Know About Decision Point and Decision Tracing

The Rules SDK API contains methods to assist with processing a decision trace. These methods process a decision trace to replace the RL names used in the trace with the aliases used in the associated dictionary. This makes the decision trace naming consistent with the naming used in the Oracle Business Rules dictionary.

The basic API for processing a decision trace requires a RuleDictionary object and a DecisionTrace object:

RuleDictionary dict = ...;
DecisionTrace trace = ...;
dict.processDecisionTrace(trace);

This code shows the processing call that converts the naming in the decision trace to use the same names, with aliases, as in the dictionary.

The Rules SDK Decision Point API contains methods that allow you configure decision tracing and retrieve the resulting trace when you invoke a decision point. The trace you retrieve from the Decision Point is internally processed using the processDecisionTrace() method, thus you do not need to call this method to process the decision trace when you are working with a decision trace from a Decision Point.

Table 7-2 shows the Decision Point API methods for setting decision trace options. For more information on these methods, see Rules Language Reference for Oracle Business Process Management.

Table 7-2 Decision Point Decision Tracing Methods

Method Description

decisionTrace

Get the decision trace produced from the call to invoke.

Returns DecisionTrace

getDecisionTraceLevel

Get the decision trace level to be used by the RuleSession. This value defaults to DECISION_TRACE_OFF, which means no trace information is gathered. Possible values are: DECISION_TRACE_OFF

DECISION_TRACE_DEVELOPMENT

DECISION_TRACE_PRODUCTION

Return Type: String

getDecisionTraceLimit

Get the decision trace limit, or maximum number of trace elements which are retrieved for the trace.

Return Type: int

setDecisionTraceLevel

Set the decision trace level to be used by the RuleSession. This parameter value is a String. Possible values are: DECISION_TRACE_OFF

DECISION_TRACE_DEVELOPMENT

DECISION_TRACE_PRODUCTION

setDecisionTraceLimit

Set the decision trace limit, or maximum number of trace elements which are retrieved for the trace.


Example 7-9 shows a sample usage of decision tracing with DecisionPoint API.

Example 7-9 Using Decision Trace from Decision Point API

DecisionPoint dp = new DecisionPointBuilder()
  .with(new DictionaryFQN("com.foo", "Bar"))
  .with("MyDecisionFunction")
  .setDecisionTraceLevel(DecisionPointBuilder.DECISION_TRACE_DEVELOPMENT)
  .setDecisionTraceLimit(24000)
  .build();
 
...
 
DecisionPointInstance dpi = dp.getInstance();
 
dpi.invoke();
 
DecisionTrace trace = dpi.decisionTrace(); // with aliases replaced

For more information on decision tracing, see "Tracing Rule Execution in Fusion Middleware Control Console" in Administering Oracle SOA Suite and Oracle Business Process Management Suite.