Skip Headers
Oracle® Business Rules User's Guide
10g Release 3 (10.1.3)
B15986-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

3 Working With Rule Author Features

This chapter describes how to use some of the more advanced features of Oracle Business Rules Rule Author. The following topics are covered:

3.1 Working with Variables

In this section you use Rule Author to add a variable that replaces a portion of the message that you print out in the Java Car Rental How-To you built in Chapter 2. Using Oracle Business Rules, a variable is similar to a public static variable in Java. You can specify that a variable is a constant or modifiable.

Perform the following steps to add a variable:

  1. Click the Repository tab and load the CarRental dictionary.

  2. Click the Definitions tab.

  3. Click the Variable node in the navigation tree. The Variable Summary page shows that no variables are defined.

  4. Click Create. This shows the Variable page.

  5. Enter DeclineMessage in the Name field.


    Note:

    When Rule Author creates a variable, it adds a "DM." to the name you enter in the Name field (DM stands for Data Model).

  6. Enter Decline Message in the Alias field.

  7. Select the Final check box (by default this box is selected).

  8. Select String in the Type box.

  9. In the Expression box, enter "Rental declined ".

    If you want to use the expression wizard to assist you with creating an expression, click the edit icon to bring up the expression builder.

  10. Click Apply (see Figure 3-1).

    Figure 3-1 Rule Author Variable Definition Page

    Rule Author Variable Definition Page
    Description of "Figure 3-1 Rule Author Variable Definition Page"

    Notes for creating Rule Author variables:

    • When you deselect the Final check box, this specifies that the variable is modifiable, for instance, in an Assign action.

    • You can only use variables specified as final variables in the test for a rule (non-finals are not allowed).


    See Also:

    "Defining Tests for Patterns with the Under Age Rule" for an example of a test for a rule.

3.2 Working with Constraints

When you want to constrain the allowed values for a field to only a specific set of values in a customizable rule, for example if you want to specify a range of values, you can use a Rule Author constraint definition.

Rule Author supports three types of constraint definitions, as shown in Table 3-1.

Table 3-1 Rule Author Constraint Types

Constraint Type Description

Range

Specifies a numeric interval.

Enumeration

Specifies a list of possible values.

Regular Expression

Specifies a regular expression to which the string value conforms. The syntax for the regular expression in these constraints follows Java's regular expression definition.



Note:

The regular expression constraint requires quotation marks around strings.

For the example in this section you define a constraint and then add the constraint to the UnderAge rule in the CarRental dictionary.

Perform the following steps to define a range constraint:

  1. Click the Repository tab and load the CarRental dictionary.

  2. Click the Definitions tab.

  3. Click the Constraint node in the navigation tree. The Constraint Summary page shows no constraints are defined.

  4. Click Create. This shows the Constraint page.

  5. Enter validAgeRange in the Name field.

  6. Select Range from the Type box. This shows a Constraint page with two new fields: Start Value and End Value.

  7. Enter 15 in the Start Value field.

  8. Enter 99 in the End Value field.

  9. Click Apply. Rule Author shows a confirmation message (see Figure 3-2).

    Figure 3-2 Rule Author Constraint Definition Page

    Rule Author Constraint Definition Page
    Description of "Figure 3-2 Rule Author Constraint Definition Page"

  10. Save the dictionary.

Next, add the validAgeRange constraint to the UnderAge rule. To use the constraint in the UnderAge rule, do the following:

  1. Click the Repository tab and load the CarRental dictionary.

  2. Using the CarRental dictionary, select the Rulesets tab.

  3. Select the UnderAge link to show the UnderAge rule.

  4. Select the edit icon in the If box. This displays the Pattern Definition page.

  5. On the Pattern Definition Page, in the constraint field, select validAgeRange (this is the second box in the Value column).

  6. Click OK. This closes the Pattern Definition Page.

  7. Click OK on the Rule page.

  8. Save the dictionary.

Use the Customization tab to verify that Rule Author lets you enter values from the specified range and rejects invalid entries.


See Also:

"Defining Tests for Patterns with the Under Age Rule" for information on using the Allowed Values field to use constraints.


Note:

If you change a constraint that is used in a ruleset, you can still save the ruleset even though it may not adhere to all the constraints.

3.3 Working with RLFacts

This example creates an RLFact named Decision that extends the CarRental rules. The RLFact has three members of String type: driverName, type, and message. Perform the following steps to create the Decision RLFact:

  1. Click the Repository tab and load the CarRental dictionary.

  2. Click the Definitions tab and click the RLFact node in the navigation tree under Facts. The RLFact Summary page shows that no RLFacts are defined.

  3. Click Create. This shows the RLFact page.

  4. Enter Decision in the Name field.

  5. Enter Car rental decision in the Alias field (see Figure 3-3).

    Figure 3-3 Rule Author Definitions Tab with RLFact Page

    Rule Author Definitions Tab with RLFact Page
    Description of "Figure 3-3 Rule Author Definitions Tab with RLFact Page"

  6. In the properties table click Create. This shows a new row in the Properties table.

  7. Enter driverName in the Name field.

  8. Select String from the box in the Type field.

  9. Enter driver name in the Alias field.

  10. Click Create. This adds another new row to the Properties table.

  11. Enter type in the Name field.

  12. Select String from the box in the Type field.

  13. Enter decision type in the Alias field.

  14. Click Create. This adds another new row to the Properties table.

  15. Enter message in the Name field.

  16. Select String from the box in the Type field.

  17. Enter message for decision in the Alias field.

  18. Click Apply. This displays a confirmation message (see Figure 3-4).

    Figure 3-4 Rule Author Definitions Tab with RLFact Properties

    Rule Author Definitions Tab with RLFact Properties
    Description of "Figure 3-4 Rule Author Definitions Tab with RLFact Properties"

  19. Click RLFact in the navigation tree. This displays the RLFact Summary page, and the new RLFact, DM.Decision.


    Note:

    When Rule Author creates an RLFact, it adds a "DM." to the name you enter in the Name field (the DM stands for Data Model).


    See Also:

    "Specifying Visibility and Object Chaining for Rule Author Drop Down Lists" for information on the Expand field shown in Figure 3-4.

3.4 Working with Functions

Oracle Business Rules lets you use built-in or user-defined functions in rule conditions and actions. In this section you use Rule Author to define a function named showDecision. You can use this function to print the results for the Java How-To.


Note 1:

The example in this section uses the CarRental dictionary and the RLFact defined in Section 3.3.


Note 2:

For RL generated from the SDK (for example, Rule Author), global variables may not be referred to directly in an RL function. For more information, see Section D.2, "Global Variables may not be Used in RL Functions".

Do the following to define the showDecision function:

  1. Click the Repository tab and load the CarRental dictionary.

  2. Using the CarRental dictionary, select the Definitions tab.

  3. Select RLFunction in the navigation tree. This shows the RLFunction Summary page.

  4. Click Create.

  5. Enter showDecision in the Name field.

  6. Enter Show Decision in the Alias field.


    Note:

    If you are defining a function in Rule Author, you must specify a valid alias in the Alias field, even though the actual function name (not the alias) must be used in the function body.

  7. Select void in the box in the Return Type field (this is the default value).

  8. Click Create in the Function Arguments table.

  9. Enter decision in the Name field.

  10. Enter Decision made for driver in the Alias field.

  11. Select Car rental decision, the alias for the Decision RLFact, in the box in the Type field.

  12. In the Function Body box, enter the following:

    DM.println( "Rental decision is " + decision.type + " for driver " + decision.driverName + " for reason " + decision.message);
    
    
  13. Click Apply. This shows a confirmation message.

  14. Click the RL Function node in the left navigation pane. You should see the RL function DM.showDecision in the summary table.

  15. Click Edit to view the function (see Figure 3-5).

    Figure 3-5 Rule Author RLFunction Page

    Rule Author RLFunction Page
    Description of "Figure 3-5 Rule Author RLFunction Page"

After creating the new RLFact Decision as specified in Section 3.3 and the new RLFunction DM.showDecision, you can update the UnderAge rule to provide an action that creates a new Decision fact. To use the Decision fact with the showDecision function, you need to create a new rule that checks for Decision facts and provides an action, using the showDecision function, to show the results.

3.5 Viewing Java Objects in a Data Model

To view the objects in a data model, including any classes or packages that you import, do the following:

  1. Click the Repository tab and load the appropriate dictionary. For example, load the CarRental dictionary.

  2. Click the Definitions tab to view the Definitions page.

  3. Expand the Facts folder and click the JavaFact node in the navigation tree to display the JavaFact Summary page.

    For the car rental sample this shows a table that includes the imported class carrental.Driver.

  4. Click the edit icon to view the Java Fact Properties and Methods.

    Description of rapencil.gif follows
    Description of the illustration rapencil.gif

Table 3-2 JavaFact Summary Fields

Field Description

Name

The name of the Java Object.

Alias

The specified alias name for the Java Object that is shown in Rule Author lists.

Visible

This box specifies if the Java Object is shown in Rule Author lists.

Support XPath Assertion

This box implies you can use the class in XPath expressions to assert XML data into a rule session.


Table 3-3 JavaFact Properties and Methods Fields

Field Description

Visible

Specifies that the property or method shows up in Rule Author lists.

Expand

Specifies that the superclass for a property or method that has a superclass shows up in Rule Author lists.

Member Variable Name

This is shown for Properties. Specifies the property name.

Type

Specifies the type for a property

Alias

This is a text field that you can modify to specify the business vocabulary for the property or object. The specified name is used when the object is shown in Rule Author drop down lists.

Method Name

This is shown for methods.

Argument Type

This is shown for methods.

Return Type

This is shown for methods.



Note:

Importing a Java class causes its super class and classes associated through fields and methods to be imported into the data model. The JavaFact Summary page table shows you the super class and the associated classes for any classes that you import.

3.5.1 Specifying Visibility and Object Chaining for Rule Author Drop Down Lists

You can specify that properties, classes, or methods are visible or not visible in Rule Author selection boxes (the selection boxes that contain classes, properties, and methods are shown when you create rules on the Rulesets Tab).


Note:

For the Java Fact How-To, you do not need to change the object chaining.

To remove the visibility of a Java object, do the following:

  1. At the top of the Java Fact page, use the Visible box to specify whether an object is visible (by default, objects are visible).

  2. Deselect the Visible box to remove the object from Rule Author selection boxes.

  3. Click OK on the Java Fact page.

To remove visibility of a Java property or method, do the following:

  1. Deselect the a property or method in the in the Properties area or the Methods area on the Java Fact page to remove the property or method from Rule Author selection boxes.

  2. Click OK on the Java Fact page.

You can specify that Rule Author selection boxes show the methods or properties one level above a specified method or property, in superclass chain, by selecting the Expand box for the method or property on the Java Fact page. The Expand box is shown in the Expand field of the Properties and Methods area. The Expand box is only shown when a method or property includes a superclass (Rule Author does not show the Expand box for primitive types).

3.6 Generating Oracle Business Rules RL Language Text

Using the RL tab, Rule Author lets you view the RL Language text that represents the data model and the rule sets associated with the dictionary data.

3.6.1 Generating and Viewing an RL Language Program

To generate and view RL Language text, do the following:

  1. Click the Repository tab and load a dictionary. For example, load the CarRental dictionary.

  2. Select the RL tab.

  3. Select the rule set of interest in the navigation tree.

  4. Click Generate RL. This shows you the RL Language text for the specified ruleset.

  5. Click Check RL Syntax to validate the RL Language text.

3.7 Configuring Rule Author Dictionary Properties

Two properties can be configured globally for an entire dictionary in Rule Author:

To configure these properties, access the Dictionary Properties page:

  1. Make sure you are connected to a repository and a dictionary is loaded.

  2. Click the Repository tab.

  3. Click the Properties secondary tab (see Figure 3-6).

Figure 3-6 Rule Author Dictionary Properties Page

Rule Author Dictionary Properties Page
Description of "Figure 3-6 Rule Author Dictionary Properties Page"

3.7.1 Using the Advanced Test Expression Option

The Advanced Test Expression check box changes the Rule Author expression mode to advanced for test expressions displayed when you edit a pattern for a rule (see Figure 3-7). Tests in a rule's condition can involve mathematical operations and conjunctions. Rule Author includes the advanced expression mode to support defining such complex expressions.

When a pattern is first created, its test expression mode depends on the Advanced Test Expression property set on the Properties page. When you select the Advanced Test Expression check box, then the advanced test expression mode is applied to all new patterns. This setting persists when the dictionary is saved. In this case, when the dictionary is loaded, all patterns are created with Advanced mode. After a pattern is created, with or without a test, it is permanently associated with the test expression mode. Thus, the Test Expression mode of a pattern cannot be changed.

In a single rule, you can use both patterns created with basic expression mode and advanced expression mode.

Figure 3-7 Pattern Definition Advanced Test Expression Page

Pattern Definition Advanced Test Expression Page
Description of "Figure 3-7 Pattern Definition Advanced Test Expression Page"

3.7.2 Using the Logging Option

The Logging box specifies the logging options. This option is useful when you need to report a problem with Rule Author. To specify logging select the Logging check box and then select the following log file properties:

  • Log Level: Error is the lowest log level and generates the least amount of output, Status is the medium log level, and Trace is the highest log level, generating the most amount of output.

  • Use the Log Directory box to specify the directory for the log. Specifying the log directory in the Log Directory box is optional (if the directory is not set, the log is displayed on the console).

  • When the Log file name is specified, the log is saved in a file with the name <log_file_name>.<last_8_session_id>. For example, if you specified RALog as the name of your log file, and the last eight digits of your session ID are 11223344, the file RALog.11223344 would be created. If no log file is specified, the log is saved in a file named RuleAuthor.<last_8_session_id>.

Click Update when you are finished specifying your logging options.

3.8 Deleting a Rule Author Dictionary

This section shows you how to delete a version in a dictionary or delete an entire dictionary.

If you want to delete an individual dictionary version, do the following:

  1. Click the Repository tab.

  2. Click the Delete secondary tab.

    If you want to delete a specific dictionary version, select a dictionary and version in the "Select dictionary version" section, then click Delete Version.

    If you want to delete an entire dictionary (and all of its versions), select the dictionary in the "Select entire dictionary" section, then click Delete.

3.9 Importing and Exporting a Dictionary

You can import a specific version of a dictionary or an entire dictionary into Rule Author. To do so:

  1. Click the Repository tab.

  2. Click the Import secondary tab.

    If the dictionary you want to import resides locally, use the section in the first bullet to specify its location. You can manually enter the path to the dictionary or click the Browse button and select the dictionary.

    If the dictionary you want to import resides on a different machine (where the Rule Author is running), you must specify the full path to the dictionary on that server.

  3. Click Import.

To export an entire dictionary:

  1. Click the Repository tab.

  2. Click the Export secondary tab.

  3. In the "Select entire dictionary" section:

    1. In the Dictionary field, select the dictionary you want to export.

    2. In the File Location field, specify the location and filename (absolute file path on the server) to which you want to export the dictionary.

  4. Click Export.

    You can also select the dictionary and click Download, which creates a link to the exported archive on the Export Dictionary page. You can then click the link and use your browser to download the archive to a location of your choice (see Figure 3-8).

    Figure 3-8 Rule Author Export Dictionary Page Showing the Download Option

    Export Dictionary Page with Download Option
    Description of "Figure 3-8 Rule Author Export Dictionary Page Showing the Download Option"

To export a specific dictionary version:

  1. Click the Repository tab.

  2. Click the Export secondary tab.

  3. In the "Select dictionary version" section:

    1. In the Dictionary field, select the dictionary you want to export.

    2. In the Version field, select the dictionary version you want to export.

    3. In the File Location field, specify the location and filename (absolute file path on the server) to which you want to export the dictionary.

  4. Click Export.

    You can also select the dictionary and version and click Download, which creates a link to the exported archive on the Export Dictionary page. You can then click the link and use your browser to download the archive to a location of your choice (see Figure 3-8).

3.10 Working with Test Rulesets

The Test Rulesets feature in the Rule Author is designed to allow you to write RL functions that test the rule sets created in Rule Author. The selected rule set and its associated data model are inserted into a Rule Session where a user-defined function is called which uses the rule set.

To use the Test Rulesets feature in Rule Author:

  1. Create a rule set you want to test. If the data model includes any Java classes, the Java classes must be included in the OC4J classpath. The easiest way to do this is to put the JAR files in the following directory, then restart OC4J:

    $ORACLE_HOME/j2ee/home/applications/ruleauthor/lib
    
    

    You can also include the Java classes as a shared library. This allows Rule Author to share the classes with other applications. To do this, login to Enterprise Manager and perform the following:

    1. Navigate to the OC4J:home page.

    2. Click the Administration tab.

    3. Find the Shared Libraries node under the Properties node and click the icon in the Go to Task column.

    4. Click Create, enter the library name and version number, then click Next.

    5. Click Add, navigate to the location of the JAR file, then click Continue.

    6. Click Finish to return to the Shared Libraries page.

    7. Find and click the link to the library you just created. Copy the absolute path to the archive.

    8. Return to the OC4J:home page.

    9. Click the Applications tab.

    10. Click the link to the Rule Author application (this was defined when you first deployed the Rule Author application).

    11. Click the ruleauthor module link.

    12. Click the Administration tab.

    13. Find the Configuration Properties node and click the Go to Task icon.

    14. In the Classpath field, paste the absolute path to the archive which you copied in Step g, then click OK.

    15. In the resulting confirmation message, click the Restart link to restart Rule Author.

  2. Create a function that has some print statements to indicate the execution of the function. In this example, a function called DM.test is created:

    1. Click the Definitions tab.

    2. Click the RLFunctions node in the navigation tree.

    3. Enter DM.test in the Name and Alias Fields.

    4. Leave void as the return type.

    5. Enter the following in the Function Body field:

      java.text.SimpleDateFormat sdf =
         new java.text.SimpleDateFormat( "MM/dd/yyyy" );
      
      assert (new carrental.Driver( "d111", "Dave", 50, "sports", "full",
                                     sdf.parse ("10/1/1969"), 0, 1, true ));
      assert (new carrental.Driver( "d222", "Abe", 15, "truck", "provisional",
                                     sdf.parse ("8/1/2004"), 0, 0, true ));
      assert (new carrental.Driver( "d333", "Lance", 44, "motorcycle", "full",
                                     sdf.parse ("6/1/2004"), 0, 1, true ));
      
      pushRuleset ("vehicleRent");
      run();
      
      

      This function asserts several facts, pushes the vehicleRent rule set onto the rule set stack, and calls run().


      Note:

      All rule sets you want to have executed must be pushed onto the stack. They are not automatically pushed simply by selecting them.

      If you wanted to enable logging, you could call the watchFacts() and watchActivations() functions.

    6. Click OK.

    7. Save the dictionary.

  3. Click the RL tab.

  4. Click the Test Rulesets node in the navigation tree. This displays the Test Rulesets page.

    Figure 3-9 Rule Author Test Rulesets Page

    Rule Author Test Rulesets Page
    Description of "Figure 3-9 Rule Author Test Rulesets Page"

    You can see the vehicleRent rule set is available. This rule set was created in Chapter 2.

  5. Select the vehicleRent rule set and move it to the Selected Rulesets column.

  6. Select the DM.test function from the Test Function list.

  7. Click Test.

    RL code is generated for the selected rule set(s), which is then inserted into a Rule Session. Then, the selected test function is called. Output from the function is printed on the screen (see Figure 3-10).

    Figure 3-10 Rule Author Test Rulesets Page with Output

    Rule Author Test Rulesets Page with Output
    Description of "Figure 3-10 Rule Author Test Rulesets Page with Output"

3.11 Invoking Rules

A rule enabled program usually invokes rules with the following steps:

  1. Pass objects to the rule engine to be asserted as facts.

  2. Run rules.

  3. Obtain results produced from rules that fired.

This section describes the best practices for using an RL function to encapsulate invoking rules. This section covers three techniques for invoking rules; the techniques differ primarily in the details required to obtain results. This section uses a sample RL function named getSubscribers. Using this routine, each approach for invoking rules looks identical from the point of view of the rule enabled program that calls the getSubscribers.

This section covers the following:

3.11.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 represent an event that gets asserted and only those subscribers registered at that time are notified.

3.11.2 Using a Global Variable to Obtain Results

Using a global variable to accumulate results is a best practice, this approach yields simpler rule conditions than the following approaches.

Example 3-1 shows the getSubscribers function asserts a TrafficIncident, initializes a global variable with a Map, invokes the Rules Engine, and returns the result Map.

Example 3-1 Obtaining Results with a RLFunction that Accesses a Global Variable

Map alerts = null;
 
function getSubscribers(TrafficIncident ti) returns Map {
   try {
      alerts = new HashMap();
      assert(ti);
      run();
      return alerts;
   } finally {
      retract(ti);
      alerts = null;
   }
}
rule incidentAlert {
   if (fact TrafficIncident ti &&
      fact IncidentSubscription s &&
      s.highway == ti.highway &&
      s.direction == ti.direction) {
         alerts.put(s.subscriber, ti);
      }
   }
}

Example 3-2 shows Java code that invokes getSubscribers and prints out the results.

Example 3-2 Sample Showing Results with Global Variable

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

Map alerts = (Map)sess.callFunctionWithArgument("getSubscribers", ti);
Iterator iter = alerts.keySet().iterator();
while(iter.hasNext()) {
   String s = (String)iter.next();
   System.out.println("Alert " + s + " : " + alerts.get(s));
}

3.11.3 Using Container Objects to Obtain Results

In this approach, one or more objects are asserted into working memory to act as a container for results. The RL code that asserts the objects keeps the references handy. As rules fire, they can add results to the containers. A container object could be one of the Java Collection classes or it could be some application specific container object. When rule evaluation is complete the container objects can be inspected to access the results.

Example 3-3 uses a java.util.Map and shows that the subscriber (key) and the incident (value) are added to the map. The getSubscribers function asserts the Map and a TrafficIncident, invokes the Rules Engine, and returns the result Map.


Note:

The Map is not reasserted even though it has been updated. In general, when an object that is being reasoned on is updated, it should be re-asserted. This use case represents an exception to that rule. The map, alerts, is just a container for results and its contents are not involved in the reasoning. Thus, it is okay not to re-assert it.

Example 3-3 Obtaining Results with a Container Object

function getSubscribers(TrafficIncident ti) returns Map {
   Map alerts = new HashMap();
   try {
      assert(alerts);
      assert(ti);
      run();
      return alerts;
   } finally {
      retract(alerts);
      retract(ti);
   }
}
rule incidentAlert {
   if (fact TrafficIncident ti &&
      fact IncidentSubscription s &&
      s.highway == ti.highway &&
      s.direction == ti.direction &&
      fact Map alerts) {
         alerts.put(s.subscriber, ti);
      }
   }
}

Example 3-2 shows Java code that invokes getSubscribers and prints out the results.

3.11.4 Using Reasoned On Objects to Obtain Results

In this approach, one or more objects are asserted into the rules engine working memory and the object references are retained in RL (in the getSubscribers function). Rule evaluation updates one or more of these objects. These objects are inspected after rule evaluation to determine the results.

In Example 3-4 the TrafficIncident class is modified to keep a java.util.Set of subscribers that need to be notified. Since the TrafficIncident object is being reasoned on, it is re-asserted. To avoid an infinite loop of rule firings for the same subscription, you need to use the subscribed method to test for matched incidents; this method prevents looping. The subscribed method returns true if a subscriber has already been added to the matched TrafficIncident. This is a common idiom in rules programming; a rule action updates a fact that is being reasoned on and, to avoid unwanted additional firings, you add a test to the condition that checks for the absence of that update.

Example 3-4 shows getSubscribers function asserts a TrafficIncident, invokes the Rules Engine, and creates and returns the result Map.

Example 3-4 Obtaining Results with a Reasoned On Object

function getSubscribers(TrafficIncident ti) returns Map {
   try {
      assert(ti);
      run();
      Map alerts = new HashMap();
      for (Iterator iter = ti.subscribers(); iter.hasNext(); ) {
         alerts.put(iter.next(), ti);
      }        
      return alerts;
   } finally {
      retract(ti);
   }
}
rule incidentAlert {
   if (fact TrafficIncident ti &&
      fact IncidentSubscription s &&
      s.highway == ti.highway &&
      s.direction == ti.direction &&
      !ti.subscribed(s.subscriber)) {
         ti.addSubscriber(s.subscriber);
         assert(ti);
      }
   }
}

Example 3-2 shows Java code that invokes getSubscribers and prints out the results.