Skip Headers
Oracle® Fusion Middleware User's Guide for Oracle Business Rules
11g Release 1 (11.1.1.6.3)

Part Number E10228-11
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

C Oracle Business Rules Frequently Asked Questions

This appendix contains frequently asked questions about Oracle Business Rules.

C.1 Why Do Rules Not Fire When A Java Object is Asserted as a Fact and Then Changed Without Using the Modify Action?

When a Java object has been asserted and then the object is changed without using the modify action, the object must be re-asserted in the Rules Engine. Therefore, if a rule associated with the changed Java object does not fire, this means that the Rules Engine did not reevaluate any rule conditions and did not activate any rules. Thus, when a Java object changes without using the modify action, the object must be re-asserted in the Rules Engine.

C.2 What are the Differences Between Oracle Business Rules RL Language and Java?

For more information on the differences between Oracle Business Rules RL Language and Java, see Appendix A in Oracle Fusion Middleware Language Reference Guide for Oracle Business Rules.

C.3 How Does a RuleSession Handle Concurrency and Synchronization?

Method calls on an Oracle Business Rules RuleSession object are thread-safe such that calls by multiple threads do not cause exceptions at the RuleSession level. However, there are no exclusivity or transactional guarantees on the execution of methods. The lowest-level run method in the Rules Engine is synchronized, so two threads with a shared RuleSession cannot both simultaneously execute run. One call to run must wait for the other to finish.

Oracle Business Rules functions are not synchronized by default. Like Java methods, Oracle Business Rules functions can execute concurrently and it is the programmer's responsibility to use synchronized blocks to protect access to shared data (for instance, a HashMap containing results data).

Any set of actions that a user wants to be executed as in a transaction-like form must synchronize around the shared object. Users should not synchronize around a RuleSession object because exceptions thrown when calling RuleSession methods may require the RuleSession object to be discarded.

For most uses of a RuleSession object in Oracle Business Rules, each thread or servlet instance should create and use a local RuleSession object. This usage pattern is roughly analogous to using a JDBC connection in this manner.

The following examples demonstrate how to use a shared RuleSession object.

For the case where Thread-1 includes the following:

ruleSession.callFunctionWithArgument("assert", singleFact1);
ruleSession.callFunctionWithArgument("assert", singleFact2);

and Thread-2 includes the following:

ruleSession.callFunction("run");
ruleSession.callFunction("clear");

In this case, the execution of the two threads might proceed as shown in Example C-1.

Example C-1 Using a Shared RuleSession Object in Oracle Business Rules

Thread-1:  ruleSession.callFunctionWithArgument("assert", singleFact1);
Thread-2:  ruleSession.callFunction("run");
Thread-2:  ruleSession.callFunction("clear"); 
Thread-1:  ruleSession.callFunctionWithArgument("assert", singleFact2); 

In Example C-1, the two facts Thread-1 asserted are never both in the RuleSession during a call to run. Notice also that only one thread calls the run method. If you use a design where multiple threads can call run on a shared RuleSession, this can create extremely hard to find bugs and there is usually no gain in performance.

All accesses to a shared RuleSession object must be synchronized to ensure the intended behavior. However, a RuleSession instance may throw an exception and not be recoverable, so do not use this object as the synchronization object. Instead, use another shared object as the synchronization point.

One can envision a shared server process producer-consumer model for RuleSession use. In this model, multiple threads assert facts to a shared RuleSession and one thread periodically calls run, reads any results, and outputs them. This ensures that thread conflicts cannot occur, because the two code segments must be executed serially and cannot be intermingled. For example, the code with shared objects, producer code, and consumer code in Example C-2, Example C-3, and Example C-4.

Example C-2 RuleSession Shared Objects

RuleSession ruleSession;
Object ruleSessionLock = new Object();

Example C-3 RuleSession Producer Code

public String addFacts(FactTypeA fa, FactTypeB fb, FactTypeC fc){
   String status = "";
   synchronized(ruleSessionLock){
     try {
       ruleSession.callFunctionWithArgument("assert", fa);
       ruleSession.callFunctionWithArgument("assert", fb);
       status = "success";
     } catch (Exception e) { 
       // a method that creates a new RuleSession loads it with rules
       initializeRuleSession(); 
       status = "failure";
     }
     return status;
}

Example C-4 RuleSession Consumer Code

public List exec(){
  synchronized(ruleSessionLock){
    try {
      ruleSession.callFunction("run");
      List results = (List)ruleSession.callFunction("getResults");
      ruleSession.callFunction("clearResults");
      return results;
    }  catch (Exception e) { 
      // a method that creates a new RuleSession loads it with rules
      initializeRuleSession();
      return null;
    }
  }
}

Note:

When multiple threads are sharing a RuleSession object, if more than one of the threads calls the run method, this can create extremely hard to find bugs and there is usually no gain in performance.

C.4 How Do I Correctly Express a Self-Join?

When working with facts, there are cases where the runtime behavior of Oracle RL may produce surprising results.

Consider the Oracle RL code in Example C-5.

Example C-5 Self-Join Using Fact F

class F {int i; }; 
rule r1 { 
  if (fact F f1 && fact F f2) { 
    println("Results: " + f1.i + ", " + f2.i); 
  }
} 
assert(new F(i:1)); 
assert(new F(i:2)); 
run(); 

How many lines print in the Example C-5 output? The answer is 4 lines because the same fact instance can match for both f1 and f2.

Thus, Example C-5 gives the following output:

Results: 2, 2 
Results: 2, 1 
Results: 1, 2 
Results: 1, 1 

Using the same example with a third F, for example (assert(new F(i:3));) then nine lines are printed and if, at the same time, a third term && fact F F3 is added then 27 lines are printed.

If you are attempting to find all combinations and orders of distinct facts, you need an additional term to in the test, as shown in Example C-6.

Example C-6 Find All Combinations of Fact F

rule r1 { 
  if (fact F F1 && fact F F2 && F1 != F2) { 
    println("Results: " + F1.i + ", " + F2.i); 
  }
} 

The code in Example C-6 gives the following output:

Results: 2, 1 
Results: 1, 2 

The simplest, although not the fastest way to find all combinations of facts, regardless of their order, is to use the code shown in Example C-7.

Example C-7 Finding Combinations of Fact F

rule r1 { 
  if (fact F F1 && fact F F2 && id(F1) < id(F2)) { 
    println("Results: " + F1.i + ", " + F2.i); 
  }
} 

Because the function id() shown in Example C-7 takes longer to execute in a test pattern than a direct comparison, the fastest method is to test on a unique value in each object. For example, you could add an integer value property "oid" to your class that is assigned a unique value for each instance of the class.

Example C-8 shows the same rule using the oid value.

Example C-8 Fast Complete Comparison

rule r1 { 
  if (fact F F1 && fact F F2 && F1.oid < F2.oid) { 
    println("Results: " + F1.i + ", " + F2.i); 
  }
} 

This problem may also arise if you attempt to remove all duplicate facts from the Oracle Rules Engine, using a function as shown Example C-9.

Example C-9 Retracting Duplicate Facts Incorrect Sample

rule rRemoveDups { 
  if (fact F F1 && fact F F2 && F1.i == F2.i) { 
    retract(F2); 
  } 
} 

However, this rule removes all facts of type F, not just the duplicates because F1 and F2 may be the same fact instance. Example C-10 shows the correct version of this rule.

Example C-10 Retracting Duplicate Facts Corrected Sample

rule rRemoveDups { 
  if (fact F F1 && fact F F2 && F1 != F2 && F1.i == F2.i) { 
    retract(F2); 
  } 
}

C.5 How Do I Use a Property Change Listener in Oracle Business Rules?

The Oracle Rules Engine supports the Java PropertyChangeListener design pattern. This allows an instance of a Java fact that uses the PropertyChangeSupport class to automatically notify the Oracle Rules Engine when property values have changed. Java facts are not required to implement this pattern to be used by Oracle Rules Engine.

Typically, changes made to values of a property of a Java object that has previously been asserted to the Oracle Rules Engine requires that the object be re-asserted in order for rules to be reevaluated with the new property value. For properties that fire PropertyChangeEvent, changing the value of those properties both changes the value and re-asserts the fact to the Oracle Rules Engine.

To implement the PropertyChangeListener design pattern in a class, do the following:

  1. Import this package in the class:

    import java.beans.PropertyChangeSupport;
    
  2. Add a private member variable to the class:

    private PropertyChangeSupport m_pcs = null;
    
  3. In the constructor, create a new PropertyChangeSupport object:

    m_pcs = new PropertyChangeSupport(this);
    
  4. Then for each setter, add the call to firePropertyChange:

    public void setName( String name ){
        String oldVal =  m_name;
        m_name = name;
        m_pcs.firePropertyChange( "name", oldVal, m_name );
    }
    
  5. Implement addPropertyChangeListener method (delegate to m_pcs):

    public void addPropertyChangeListener(PropertyChangeListener pcl){
        m_pcs.addPropertyChangeListener( pcl );
    }
    
  6. Implement removePropertyChangeListener method (delegate to m_pcs):

    public removePropertyChangeListener(PropertyChangeListener pcl){
        m_pcs.removePropertyChangeListener( pcl );
    }
    

When deciding whether to design your application to always explicitly re-assert modified objects or implement the PropertyChangeListener design pattern, consider the following:

C.6 What Are the Limitations on a Decision Service with Oracle Business Rules?

There are some limitations for using Business Rules with a BPEL process, including the following:

For an additional restriction, see Appendix D, "How Are Decision Service Input Output Element Types Restricted?".

For information on setting XML fact type visible option, see Section 3.2, "Working with XML Facts".

C.7 How Do I Put Java Code in a Rule?

You do not actually put Java code in a rule. However, you can invoke a Java method from a rule condition or action.

C.8 Can I Use Java Based Facts in a Decision Service with BPEL?

Oracle BPEL PM can invoke only decision functions exposed as a decision service, and this means that the decision function inputs and outputs must be XML fact types.

You can use an existing ruleset or decision function that uses Java fact types if you convert the input XML facts to Java facts. For example, you could create some rules in a ruleset, named convertFromXML, and put this ruleset before the Java ruleset in the decision function ruleflow. Similarly, you could create a ruleset to convert from Java facts to output XML facts and put this ruleset after the Java ruleset in the decision function ruleflow.

Alternatively, if your rules use only properties, and no methods or fields, from the Java fact types you can replace the Java fact types with XML fact types as follows:

  1. Delete the Java fact types (first making careful note of the aliases of the fact types and properties).

  2. Import similar XML fact types and edit the aliases of the fact types and properties to be the same as the deleted Java fact types and properties.

C.9 How Do I Enable Debugging in a BPEL Decision Service?

To enable debugging output during ruleset execution for a BPEL Decision Service, you enable the SOA rules logger. When the SOA rules logger is set to TRACE level then the output of watchAll is logged to the SOA diagnostic log. When you change the logging level using Fusion Middleware Control Console, you do not need to redeploy the application to use the specified level.

For information on using the SOA oracle.soa.service.rules and oracle.soa.services.rules.obrtrace loggers, see Oracle Fusion Middleware Administrator's Guide for Oracle SOA Suite and Oracle Business Process Management Suite.

C.10 How Do I Support Versioning with Oracle Business Rules?

Versioning is supported in Oracle Business Rules in two ways:

Note: It is possible for a server application to respond to dictionary changes as they are made visible to the application in MDS. The rule service engine (decision service) does this automatically. For non-SCA application, this can be done using the RuleRepository interface. At this time, they way to support an "in-draft" version is by using the sandbox feature of MDS. The Oracle Business Rules RuleRepository interface supports this.

C.11 What is the Priority Order Using Priorities with Rules and Decision Tables?

The priority for rules and decision tables is highest to lowest, with the higher priority rule or Decision Table executing first. For example, if you create rules with priorities 1-4, they would be executed in the execution priority order 4,3,2,1. Using Rules Designer you can select a priority from a predefined named priority list or enter a positive or negative integer to specify your own priority level. The default priority is medium (with the integer value 0). For more information, see Section 4.5.5, "How to Set a Priority for a Rule".

Note, however, you should try to avoid priorities as much as possible since they break the purely declarative model of rules. If you find yourself using a lot of priorities, then generally it is best to try to restructure your rule patterns and tests to avoid conflicts, or divide the rules into multiple rulesets using ruleflow if they are intended to be run in a certain order. A conflict is a case when more than one rule in a ruleset is able to fire. For example, if a "gold customer" rule says to make a customer that spends over $1000 a gold customer, and a "silver customer" rule says to make a customer that spends over $500 a silver customer, then when a customer spends $1100 there is a conflict. Rather than prioritize the rules, it is more declarative to change the "silver customer" rule to test for customers that spend between $500 and $1000. This conflict analysis and conflict avoidance is particularly easy if you use Decision Tables. For more information on Decision Tables, see Chapter 5, "Working with Decision Tables".

You use ruleflow, that is the ruleset stack, to order rulesets. For information on working with the ruleset stack, see Oracle Fusion Middleware Language Reference Guide for Oracle Business Rules.

C.12 Why do XML Schema with xsd:string Typed Elements Import as Type JAXBElement?

According to the JAXB 2.0 spec, the default type mapping for elements that have minOccurs="0" and nillable="true" is JAXBElement<T>, where T is the default mapping of the type defined for the element. For example, xsd:string maps to JAXBElement<String>, xsd:int maps to JAXBElement<Integer>, and xsd:integer maps to JAXBElement<BigInteger>. This is because nillable="true" means the user has defined a semantic difference between a element not being defined in a document, with minOccurs=0, it does not have to be defined, and an element being defined but having the attribute nil="true". This is a subtle difference and is often used to define the difference between an unknown value and a value known to be "no value".

To use the JAXBElement-typed property in a rule, the property must be first checked for non-null, and then the "value" property or getValue() method can be used retrieve a value of the underlying type:

fact FactType1 &&
    FactType1.prop1 != null &&
    FactType1.prop1.value == "abc"

Alternatively, you may want to define a customized JAXB binding so nillable elements are mapped to type T rather than JAXBElement<T>. However, this is a lossy conversion, as you no longer are able to determine the difference between a non-existent element and a nil one. This does make the nillable attribute less useful, but it does allow you to explicitly define an element as nil in your document, similarly to how in Java an Object-typed field is initialized to null by default or you can explicitly initialize it to null.

There are several ways to do this. In both cases, add these attributes to the top-level xsd:schema element start tag:

xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0"
  1. To specify ALL properties to use the binding, add this immediately inside the xsd:schema opening tag:

    <xsd:annotation>
        <xsd:appinfo>
            <jaxb:globalBindings generateElementProperty="false"/>
        </xsd:appinfo>
    </xsd:annotation>
    
  2. To specify only specific properties use the binding, add an annotation like this to each desired element:

    <xsd:element name="stringElement2" type="xsd:string" minOccurs="0" nillable="true">
        <xsd:annotation>
            <xsd:appinfo>
                 <jaxb:property generateElementProperty="false" />
            </xsd:appinfo>
        </xsd:annotation>
    </xsd:element>
    
  3. Add the definitions to an external customizations file and pass it as an argument when adding the schema to the datamodel. This can only be done when programmatically calling the SchemaBrowser class and is not exposed in Rule Designer.

C.13 Why Are Changes to My Java Classes Not Reflected in the Data Model?

Do not import classes that have been compiled into the "SCA-INF/classes" directory. Classes in this directory cannot be reloaded into the datamodel when they change.

C.14 How Do I Use Rules SDK to Include a null in an Expression?

You can use the following Rules SDK code to include a null value:

SimpleTest test = pattern.getSimpleTestTable().add();
test.getLeft().setValue(attr);
test.setOperator(Util.TESTOP_NE);
test.getRight().setValue("null");

C.15 Is WebDAV Supported as a Repository to Store a Dictionary?

The Web Distributed Authoring and Versioning (WebDAV) repository is not supported to store a dictionary in Oracle Fusion Middleware 11g Release 1 (11.1.1) Oracle Business Rules. Oracle Business Rules supports using an MDS (file backed or Database backed) repository for storing dictionaries.

C.16 Using a Source Code Control System with Rules Designer

There are special considerations when you use Rules Designer and a source control system, such as CVS or Subversion. When you use a source code control system with Rules Designer you need to specify that rule dictionary files in your project are recognized as "binary" files instead of "text" files. The rule dictionary files are XML documents and by default the source code control system treats these files as text files. However, rule dictionary files cannot be merged because the files contain semantic structure. If a rule dictionary file is treated as a text file and then changed, the source control system attempts to merge the file with a "trivial" merge. Using a trivial merge creates a semantically invalid dictionary file which cannot be unmarshalled into a RuleDictionary object.

Thus, when you use a source code control system with rule dictionary files, .rules files, you need to make sure the source code control system treats the files as binary files. There are configuration options you need to set to specify that the system treats dictionary files as binary files. For example, in the Subversion source code control system you can set the MIME type with the svn:mime-type file property. For more information, see

http://svnbook.red-bean.com/nightly/en/svn.advanced.props.file-portability.html#svn.advanced.props.special.mime-type

When you set the source code control system options to specify the binary file type, this allows the source code control system, for example tortoiseSVN, to treat the rules dictionary files correctly, as binary files.