Developing Static Methods

CER has support for a variety of expressions which are likely to provide the calculations you need.

If you have a business calculation which cannot be implemented using CER's expressions, then CER supports the call expression to allow you to call out from your rule set to a static method on a custom Java class. The CER Editor provides few rule elements, e.g., "call" to allow users to define a static method on a custom Java class. See "call" rule element in Call.

Here is an example rule set which calls out to a Java method:

<?xml version="1.0" encoding="UTF-8"?>
<RuleSet name="Example_StaticMethodDevelopment"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation=
"http://www.curamsoftware.com/CreoleRulesSchema.xsd">
  <Class name="Income">

    <Attribute name="paymentReceivedDate">
      <type>
        <javaclass name="curam.util.type.Date"/>
      </type>
      <derivation>
        <specified/>
      </derivation>
    </Attribute>

    <Attribute name="amount">
      <type>
        <javaclass name="Number"/>
      </type>
      <derivation>
        <specified/>
      </derivation>
    </Attribute>

  </Class>

  <Class name="Person">

    <Attribute name="incomes">
      <type>
        <javaclass name="List">
          <ruleclass name="Income"/>
        </javaclass>
      </type>
      <derivation>
        <specified/>
      </derivation>
    </Attribute>

    <Attribute name="mostRecentIncome">
      <type>
        <ruleclass name="Income"/>
      </type>
      <derivation>
        <!-- In early development, the method
             identifyMostRecentIncome_StronglyTyped would be used.

             In practice, you would not maintain two versions of
             each method; you would simply weaken the argument
             and return types, and keep a single method.
          -->

        <call class="curam.creole.example.BestPracticeDevelopment"
          method="identifyMostRecentIncome_WeaklyTyped">
          <type>
            <ruleclass name="Income"/>
          </type>
          <arguments>
            <this/>
          </arguments>
        </call>
      </derivation>
    </Attribute>
  </Class>

</RuleSet>

When you develop your static method, you can start by using CER's generated Java classes as argument types and/or return type for the method:

package curam.creole.example;

import java.util.List;

import curam.creole.execution.session.Session;
import
 curam.creole.ruleclass.Example_StaticMethodDevelopment.impl.Income;
import
 curam.creole.ruleclass.Example_StaticMethodDevelopment.impl.Person;

public class BestPracticeDevelopment {

  /**
   * Identifies a person's most recent income.
   *
   * Note that this calculation can be performed using CER
   * expressions, but is shown here in Java just to illustrate the
   * use of generated types when developing static Java methods for
   * use with CER.
   *
   * This method is suitable only for use in development; for
   * production, see the
   * {@linkplain #identifyMostRecentIncome_WeaklyTyped} below.
   *
   * In practice, you would not maintain two versions of each
   * method; you would simply weaken the argument and return types,
   * and keep a single method.
   */
  public static Income identifyMostRecentIncome_StronglyTyped(
      final Session session, final Person person) {

    Income mostRecentIncome = null;
    final List<? extends Income> incomes =
        person.incomes().getValue();
    for (final Income current : incomes) {
      if (mostRecentIncome == null
          || mostRecentIncome.paymentReceivedDate().getValue()
              .before(current.paymentReceivedDate().getValue())) {
        mostRecentIncome = current;
      }
    }

    return mostRecentIncome;
  }
}

Once the Java method is working to your satisfaction, you must weaken the types to use dynamic rule objects instead of the generated Java classes (which should not be used in a production environment):

/**
   * Identifies a person's most recent income.
   *
   * Note that this calculation can be performed using CER
   * expressions, but is shown here in Java just to illustrate the
   * use of generated types when developing static Java methods for
   * use with CER.
   *
   * This method is suitable for use in production; for initial
   * development, see
   * {@linkplain #identifyMostRecentIncome_StronglyTyped} above.
   *
   * In practice, you would not maintain two versions of each
   * method; you would simply weaken the argument and return types,
   * and keep a single method.
   */
  public static RuleObject identifyMostRecentIncome_WeaklyTyped(
      final Session session, final RuleObject person) {

    RuleObject mostRecentIncome = null;
    final List<? extends RuleObject> incomes =
        (List<? extends RuleObject>) person.getAttributeValue(
            "incomes").getValue();
    for (final RuleObject current : incomes) {
      if (mostRecentIncome == null
          || ((Date) mostRecentIncome.getAttributeValue(
              "paymentReceivedDate").getValue())
              .before((Date) current.getAttributeValue(
                  "paymentReceivedDate").getValue())) {
        mostRecentIncome = current;
      }
    }

    return mostRecentIncome;

  }
CAUTION:
If you change the implementation of a static method, CER will not automatically know to recalculate attribute values that were calculated using the old version of your static method.

Once a static method has been used in a production environment for stored attribute values, rather than changing the implementation you should instead create a new static method (with the required new implementation), and change your rule sets to use the new static method. When you publish your rule set changes to point to the new static method, CER will automatically recalculate all instances of the affected attribute values.

Any static method (or property method) invoked from CER: