Skip Headers

Oracle® Business Rules User's Guide 10g Release 3 (10.1.3) B15986-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# 6 Using Oracle Business Rules SDK

Oracle Business Rules SDK (Rules SDK) provides APIs that a developer can use to write customized applications that access, create, or modify rules and data models (and all the information stored in an Oracle Business Rules dictionary). Using Rules SDK APIs, you can create, modify, and access dictionary data using well defined interfaces and you can use the APIs to build customized rules enabled applications.

You can use the Rules SDK APIs in a rule enabled application to access existing rules and then run the rules engine, or in an application that you write to access, create, or edit rules and data model information.

This chapter introduces the Oracle Business Rules SDK APIs.

This chapter covers the following topics:

- Rules SDK building blocks

- Working with a Repository and a Dictionary

- Working with a Data Model

- Creating a DataModel

- Using RuleSets and Creating and Modifying Rules

## 6.1 Rules SDK building blocks

The top level Rules SDK package, `oracle.rules.sdk,` includes the following packages:

- `oracle.rules.sdk.repository`

- `oracle.rules.sdk.dictionary`

- `oracle.rules.sdk.editor.datamodel`

- `oracle.rules.sdk.editor.ruleset`

- `oracle.rules.sdk.exception`

The Rules SDK interface follows the Java Bean model and includes getters and setters for each bean property. For example, `setName("somevalue")` sets the `name` property of the individual instance.

In addition to bean interfaces, the Rules SDK provides a hash get and put style interface. The bean interfaces are generally useful, but there is a least one GUI framework in which the HashMap style is necessary.

## 6.2 Working with a Repository and a Dictionary

Oracle Business Rules dictionaries are stored in a repository. Prior to accessing a dictionary, access to its repository must be established. This requires specifying the type of repository to access and the initialization parameters required by that specific repository type. As shipped, Rule Author supports a WebDAV (Web Distributed Authoring and Versioning) repository and a file repository.

Table 6-1 shows the initialization parameter keys for a WebDAV repository. The repository type key is `oracle.rules.sdk.store.webdav`.

Table 6-1 WebDAV Repository Type Parameter Initialization Keys

Parameter | Key | Description
--- | --- | ---
URL | `oracle.rules.sdk.store.webdav.url` | The URL for the desired WebDAV rule repository. This parameter is required.
Proxy Host | `oracle.rules.sdk.store.webdav.proxyHost` | The host name of the proxy server. This is only required if you have a proxy server between the server on which Rule Author is running and the WebDAV server.
Proxy Port | `oracle.rules.sdk.store.webdav.proxyPort` | The port to use for the proxy server. This is only required if you have a proxy server between the server on which Rule Author is running and the WebDAV server.

Table 6-2 shows the initialization parameter keys for a file repository. The repository type key is `oracle.rules.sdk.store.jar`.

Table 6-2 File Repository Type Parameter Initialization Key

Parameter | Key | Description
--- | --- | ---
File Path | `oracle.rules.sdk.store.webdav.path` | The path to the file that contains the rule repository. This parameter is required.

### 6.2.1 Establishing Contact with a WebDAV Repository

Example 6-1 shows how to establish access to a WebDAV repository.

Example 6-1 Establishing Access to a WebDAV Repository

    String url;     // the URL for the WebDAV repository
    Locale locale;  // the desired Locale

    // The following code assumes that the url and locale have been set appropriately
    RepositoryType rt =
       RepositoryManager.getRegisteredRepositoryType("oracle.rules.sdk.store.webdav");
    RuleRepository repos = RepositoryManager.createRuleRepositoryInstance(rt);
    RepositoryContext rc = new RepositoryContext();
    rc.setLocale(locale);
    rc.setProperty("oracle.rules.sdk.store.webdav.url", url);
    repos.init(rc);

If the WebDAV repository has been configured to require authentication, then the following must be performed:

- Configure a wallet with the required user name(s) and password(s).

- Create an instance of the `oracle.rules.sdk.callbacks.WalletCallback` class and set it in the `RepositoryContext` prior to calling the `init` method.

In Example 6-2, `/wallets/rules_wallet` is the path to the wallet configured with the credentials for WebDAV authentication:

Example 6-2 Configuring a Wallet for Authentication

    WalletCallback callback = new WalletCallback("/wallets/rules_wallet", null);
    rc.setSensitiveDataCallback(callback);

### 6.2.2 Establishing Contact with a File Repository

Example 6-3 shows how to establish access to a file repository.

Example 6-3 Establishing Access to a File Repository

    String path;     // the path to the file repository
    Locale locale;  // the desired Locale

    // The following code assumes that the path and locale have been set appropriately
    RepositoryType rt =
       RepositoryManager.getRegisteredRepositoryType("oracle.rules.sdk.store.jar");
    RuleRepository repos = RepositoryManager.createRuleRepositoryInstance(rt);
    RepositoryContext rc = new RepositoryContext();
    rc.setLocale(locale);
    rc.setProperty("oracle.rules.sdk.store.jar.path", path);
    repos.init(rc);

### 6.2.3 Loading a Dictionary

Now, a dictionary may be loaded either by specifying the dictionary name, in which case, the default version of the dictionary is loaded with:

    RuleDictionary dictionary = repos.loadDictionary(dictionaryName);

or by specifying both the dictionary name and version with:

    RuleDictionary dictionary = repos.loadDictionary(dictionaryName,
                                                     dictionaryVersion);

These examples are applicable to both file and WebDAV repositories.

## 6.3 Working with a Data Model

The Rules SDK data model contains the fact types, internal variables, constraints, and functions that you use to create rules. The fact types from the data model can be reasoned on in corresponding rules. Oracle Business Rules variables contain information that rules share. Oracle Business Rules functions provide for logic reuse for rules. Constraints limit the set of valid values for rule customization.

Note: To import existing Java classes or XML schemas, the Rule Author application must be used. After the classes or schemas are imported with Rule Author, the repository may be used by the SDK. Future versions of the SDK will have extensions to allow for Java classes and XML schemas to be imported directly.

After you use a repository to create or open a `RuleDictionary`, you can use the Rules SDK to create a data model in the dictionary. A `RuleDictionary` can access the internal data structures necessary to create a `DataModel` instance.

The data model shown in the examples is this chapter includes the Java FactTypes that are imported from a sample package named `email`. The `email` package was imported using Rule Author. The classes and properties shown in Table 6-3 were populated by importing `email.jar`.

Table 6-3 Sample email Package Classes

Name | Description | Type
--- | --- | ---
`email.ElectronicMessage` | Represents the occurrence of a message | Java FactType
`email.EmailAddress` | Represents an email address | Java FactType
`email.EmailAddressList` | Represents a list of email addresses | Java FactType

In the data model for the spam processing example, using the `email` package, the data model supports inferencing by creating an `RLFact` named `SpamFound`. To contain a global count, we create a variable named `spamCounter`, and the constant `String` variable indicates spam. A function named `killSpam` provides an action when the rules detect that an email message is spam. Table 6-4 shows these data model components.

Table 6-4 Sample Data Model Types for Handling email Package

Name | Description | Type
--- | --- | ---
`SpamFound` | Asserted when email message is determined to be spam | RL FactType
`spamCounter` | Accumulates count of spam messages | variable
`SpecialOffer_CONST` | Constant containing the `String` "Special Offer" | constant variable
`fKillSpam` | Called when spam found to delete spam | RL Function

### 6.3.1 Creating a DataModel

After you create and open a `RuleDictionary`, you can use the Rules SDK to create an `editor.DataModel`. The `RuleDictionary` can access the internal data structures necessary to create a `DataModel` instance.

For example,

    eDM = new oracle.rules.sdk.editor.datamodel.DataModel(m_dict);

The basis of the DataModel type system is the FactType. A FactType is defined as a primitive, Java, XML, or RL FactType. A Primitive FactType is fixed, and includes Java primitives (for example: `String`, `int`, or `double`). The Rules SDK automatically creates primitive types when you create a `RuleDictionary`. You create Java and XML FactTypes when you import classes from jar file, a class, or a schema file. You can create RL FactTypes directly using the Rules SDK. The Java, XML, and RL FactTypes define classes and may have associated properties, which represent the JavaBean defined properties, and methods.

### 6.3.2 Creating DataModel Components

You create each part of the data model using the appropriate `ModelComponentTable`. The sequence required to create a new instance, `Function`, `FactType`, `Variable`, or `Constraint`, is the same:

- Instantiate the appropriate table in the data model.

- Invoke the table instance `add()` method.

Example 6-4 shows how you create a Function instance:

Example 6-4 Creating a Function Instance

    FunctionTable ft = eDM.getFunctionTable();
    Function fKillSpam = ft.add();

To import existing Java classes or XML schemas, the Rule Author application must be used. After the classes or schemas are imported with Rule Author, the repository may be used by the SDK. Future versions of the SDK will have extensions to allow for Java classes and XML schemas to be imported directly.

### 6.3.3 Creating a Function Argument List

Using the Rules SDK you create argument lists for functions using a `FormalParameterTable`. Each `FormalParameter` entry represents a parameter. The first parameter is the first (zero) entry in the `FormalParameterTable`, the second parameter is the second Entry, and so on. Variables may be constants, which may not be assigned a value after the original initialization. The `setFinal()` method controls the constant behavior. Each `FormalParameter` has a type and a name. The type of a formal parameter is selected from the available FactTypes.

The code in Example 6-5 creates a `FormalParameterTable` for the `email` sample.

Example 6-5 Creating a FormalParameterTable

    // define the parms of the function
    // basically just an instance of ElectronicMessage
    // and a String to explain what triggered this
    FormalParameterTable fKillSpamParmTable = fKillSpam.getFormalParameterTable();
    FormalParameter fp1 = fKillSpamParmTable.add();
    FormalParameter fp2 = fKillSpamParmTable.add();
    fp1.setName("emsg");
    fp1.setAlias("Email Message");

    // use the alias for the email.ElectronicMessage fact type
    // will be in the getType_Options list
    fp1.setType("email.ElectronicMessage");
    fp2.setName("reason");
    fp2.setAlias("reason");

     // use the primitive type for String
     // will be in the getType_Options list
    fp2.setType("String");

### 6.3.4 Creating an Initializing Expression

Using the Rules SDK, variables contain state internal to a RuleSet. Each variable must have a type and an initializing Expression. The variable type of is chosen from the list of possible FactTypes (all FactTypes defined in the DataModel).

There are two types of expressions:

- `Expression`

  This type of expression must follow the form:

      operand operator operand

  The operands and operators available for an `Expression` are more limited than than those for an `AdvancedExpression`. For example, an `Expression` does not allow an operand to be a function requiring parameters.

- `AdvancedExpression`

  This type of expression allows for the full range of operands and operators.

It is recommended that you use an `AdvancedExpression` to initialize an expression. Example 6-6 shows how to set a variable's initial value.

Example 6-6 Setting a Variable's Initial Value

    InitialValue iv = var.getValue();
    AdvancedExpression adv = iv.getAdvancedExpression();
    adv.insert(0, "\"FIXEDVALUE\"");

### 6.3.5 Creating RL Function Bodies

RL Function bodies are composed of strings of RL Language. They may refer to any of the Function parameters, or any global Variable. Enter function bodies as a String that must be syntactically correct RL Language (see Example 6-7).

Example 6-7 Creating a Function Body

    //set the body of the function
    // in this case just pretty print a message
    fKillSpam.setBody(" println(\" email from: \" + emsg.getSender() + \"  because \" + reason)" );

## 6.4 Using RuleSets and Creating and Modifying Rules

Using the Rules SDK, a rule is a conditional expression, referred to as a condition, and a set of actions that execute if the condition evaluates to true. A rule condition is composed of a set of patterns. A pattern delineates the match type and includes tests against that type and other types that appear in preceding pattern (order has meaning). Rule actions can be calls, assignments, retractions, and assertions.

Figure 6-1 shows the general container hierarchy for a RuleSet.

Figure 6-1 Rules SDK RuleSet Container Hierarchy

Description of "Figure 6-1 Rules SDK RuleSet Container Hierarchy"

The Rules SDK provides classes that represent each of these objects, all classes descend from `RuleComponent`. For collections, for example rules in a ruleset, patterns in a rule, or actions in a rule, the Rules SDK provides a class that is descended from `RuleComponentTable` to manage a specific collection (see Figure 6-2). The `RuleComponentTable` sub-class provides a specialized `add()` method for the particular sub-class that the table represents.

Figure 6-2 Rules SDK RuleComponents

Description of "Figure 6-2 Rules SDK RuleComponents"

The Rules SDK components describing the XML schemas, Java Classes, RL Global variables, and RL Functions are located in the data model (stored in the dictionary). Typically, `RuleComponent` instances refer to data model entities.

### 6.4.1 Creating a RuleSet

Generally, the sequence you use to create a `RuleComponent` is:

- Create a `RuleSet` by use of a `RuleSet` constructor.

- Create any children of the `RuleSet` by `add()` methods on the appropriate table (`PatternTable`, `ActionTable`, `ExpressionTable`, `SimpleTestTable`).

The Rules SDK API provides classes that represent collections in a `RuleSet`. Each of these objects descend from `RuleComponent`. For collections, for example rules in a ruleset, or patterns in a rule or actions in a rule, the Rules SDK provides classes that are descended from `RuleComponentTable` class to manage a specific collection. The `RuleComponentTable` sub-class provides a specialized `add()` method for the particular sub-class represented by the table.

The code in Example 6-8 creates a `RuleSet` for the email sample,

Example 6-8 Creating a RuleSet

    oracle.rules.sdk.editor.ruleset.RuleSet rs = null;
      try
        {
          rs = new oracle.rules.sdk.editor.ruleset.RuleSet(m_dict);
          m_curBean = rs;
          rs.setName("SpamRuleSet");
        }
        catch (Exception e)
        {
          System.out.println(" create RuleSet FAILED");
          addException(e);
          return;
        }

### 6.4.2 Adding a Rule to a Ruleset

The Rules SDK API provides classes that represent the objects in a `RuleSet`. Each of these objects descend from `RuleComponent`. For collections, for example rules in a ruleset, or patterns in a rule or actions in a rule, the Rules SDK provides classes that are descended from `RuleComponentTable` class to manage a specific collection. The `RuleComponentTable` sub-class provides a specialized `add()` method for the particular sub-class represented by the table.

There are several classes that are not parts of collections. To access these classes use the the parent bean with the getter interface. For example, acquire the `AdvancedExpression` by invoking `getAdvancedExpression()` on the correct `Pattern` instance.

The code in Example 6-9 shows how to add a rule to a table in RuleSet.

Example 6-9 Adding a Rule to a Table in a RuleSet

    //add rule to the table
    oracle.rules.sdk.editor.ruleset.Rule r = rs.getRuleTable().add();
    r.setName("DetectSpamRule");

### 6.4.3 Adding a Pattern to a Rule

The Rules SDK API provides the `Pattern` class that represents a pattern. The `getPatternTable` sub-class provides a specialized `add()` method for adding a pattern object, as shown in Example 6-10.

Example 6-10 Adding a Pattern to a Rule

    //add pattern to the rule
    oracle.rules.sdk.editor.ruleset.Pattern p = r.getPatternTable().add();

    //set pattern
    p.setVariable("xx");
    p.setFactType( "email.ElectronicMessage");
    p.setTestForm("Advanced");

The `TestForm` property defines the type of test associated with the pattern.

### 6.4.4 Adding a Test to a Pattern

Every `Pattern` may have Tests associated with the `Pattern`. Tests may take the form of `SimpleTest` or `AdvancedExpression`. A `Pattern` may have an unlimited number of Tests.

The Rules SDK "ANDs" Tests together when generating the RL Language. For example, the test used for the email example requires a function with parameters. This requires an `AdvancedExpression` (see Example 6-11).

Example 6-11 Adding a Test to a Pattern

    AdvancedExpression adv = (AdvancedExpression)p.get("AdvancedExpression");

    // FUNCTION and Variable complex expression
    adv.put("Function", "containsString");
    adv.insert(0, adv.getFunctionDescription());

    //System.out.println(" function is: <<" + adv.getFunctionDescription() + ">>");
    //set the function parms
    // normally the cursor position is set by user input actions
    adv.setVariable("SPECIAL OFFER");
    adv.replace(17, 57, adv.getVariable() );
    adv.insert( ((String)adv.getValue()).length() , "," );
    adv.setVariable("message.subject");
    adv.insert( ((String)adv.getValue()).length() + 1,
    adv.getVariable() );
    adv.insert( ((String)adv.getValue()).length() , " )" );
    //since boolean, this is a single operator no need for anything else

If the test is of the form:

    operand operator operand

where neither operand is a function requiring parameters, then a `SimpleTest` may be used. For example, if the pattern variable name is "emsg" and the test is "emsg.sender == david@fun.com," a simple test would look like Example 6-12:

Example 6-12 A Simple Test

    // use the simple form of tests
    p1.put("TestForm", Pattern.TEST_FORM_SIMPLE);

    //////////////////////////////////////////////////////////////////////
    // add a SimpleTest to the Pattern
    // emsg.sender == "david@fun.com"
    //////////////////////////////////////////////////////////////////////

    //create a simple test
    SimpleTest simple = p1.getSimpleTestTable().add();

    //
    // emsg.sender == "david@fun.com"

    // set the left side
    Expression lhs = simple.getLeft();
    lhs.setForm(Expression.FORM_SINGLE_TERM);

    lhs.setSingleTermValue("emsg.sender");

    // set the operator
    simple.setOperator("==");

    // set the right hand side
    Expression rhs = simple.getRight();
    rhs.setForm(Expression.FORM_ADVANCED);

    AdvancedExpression radv = rhs.getAdvancedExpression();
    radv.insert(0, "\"david@fun.com\"");

### 6.4.5 Adding an Action to a Rule

The Rules SDK supports the following types of `Actions`:

- Assert New

- Assert

- Assign

- Call

- Retract

- RL

The setting in the `setForm` property of an action defines the type of action. Add an action using the `add()` method of the `getActionTable` instance associated with a particular rule (see Example 6-13).

Example 6-13 Defining an Action Type

    //////////////////////////////////////////////////////////////////////
    // Add a action to retract the instance of SpamFound
    //////////////////////////////////////////////////////////////////////
    act = spamRule.getActionTable().add();
    act.setForm(Action.FORM_RETRACT);
    act.setTarget("spamMessage");  // see above setVariable

    //////////////////////////////////////////////////////////////////////
    // Add a action to call the kill spam function
    //////////////////////////////////////////////////////////////////////
    act = spamRule.getActionTable().add();
    act.setForm(Action.FORM_CALL);
    act.setTarget("kill spam");
    //see the datamodel fn definitions, alias for fnKillSpam

    Expression exp1 = act.getExpression(0);
    Expression exp2 = act.getExpression(1);

    exp1.setForm(Expression.FORM_ADVANCED);
    exp2.setForm(Expression.FORM_ADVANCED);
    AdvancedExpression adv1 = exp1.getAdvancedExpression();
    AdvancedExpression adv2 = exp2.getAdvancedExpression();

    adv1.setVariable("spamMessage.Spam Email");
    adv1.insert(0, adv1.getVariable());

    adv2.setVariable("spamMessage.Why is this spam");
    adv2.insert(0, adv2.getVariable());

### 6.4.6 Notes for Adding RuleSets and Rules

The order in which you add components to a `RuleSet` is important. Use the parent object to create a required child object. For example, after you create a `RuleSet` instance, you can add rules the `RuleTable` instance for the `RuleSet`. After you create the `RuleSet`, then you can add a Rule to the `RuleSet` using the `add()` method for the `RuleTable`. In turn, then add a rule pattern to the rule using the `PatternTable.add()` method. Finally, to create a test in the `Pattern` access the `AdvancedExpression` using `getAdvancedExpression()` or for standard mode tests, use `SimpleTestTable.add()`.