Externe Funktionen mithilfe von Ausdrücken aufrufen

Ausdrücke finden sich an vielen Stellen eines Scripts, wo sie das Verhalten von Schleifen, Bedingungen u.ä. definieren. Informationen hierzu finden Sie im Anhang zur Ausdruckssyntax des Handbuchs Authoring Scripts using Intelligent Evidence Gathering(IEG).

Diese Ausdrücke können auf Antworten verweisen, sie mithilfe verschiedener Operatoren kombinieren und auch Funktionen aufrufen (außer bei Verwendung für dynamische bedingte Cluster, da diese Ausdrücke im Browser bewertet werden).

Die oben beschriebenen Funktionen werden als angepasste Funktionen bezeichnet und unter Verwendung von Java-Code definiert. Je nach ihrer Verwendung können sie einen der folgenden zwei Typen aufweisen:

Ein Praxisbeispiel, bei dem der Aufruf einer externen Funktion erforderlich wäre, ist die Validierung einer US-Postleitzahl, die der Benutzer eingegeben hat, und das Füllen des Felds für den Bundesstaat anhand der eingegebenen Postleitzahl. Im Folgenden werden zwei unterschiedliche Verwendungsarten veranschaulicht.

Das Datenbankschema muss wie folgt erweitert werden, um die folgenden zwei Attribute zur Personenentität hinzuzufügen:

Abbildung 1. Personenattribute zum DS-Schema hinzufügen
<xsd:attribute name="state" type="IEG_STRING"/>
<xsd:attribute name="zipCode" type="IEG_STRING"/>

Zunächst soll die Postleitzahl anhand der Angabe für den Bundesstaat validiert werden, eine sehr simple Anwendung. Die Postleitzahl muss fünf Ziffern enthalten, von denen die ersten drei für den Bundesstaat stehen.

Die schon erwähnte Seite mit den persönlichen Angaben und die entsprechende Zusammenfassungsseite können mit zwei zusätzlichen obligatorischen Fragen modifiziert werden: "state" und "zipCode" ("Bundesstaat" und "Postleitzahl"):

Abbildung 2. Die Fragen "state" und "zipCode" in der Scriptdefinition
<question id="state" mandatory="true">
    <label id="State.Label">
        State:
    </label>
    <help-text id="State.HelpText">
        The state you live in
    </help-text>
</question>
<question id="zipCode" mandatory="true">
    <label id="ZipCode.Label">
        ZIP Code:
    </label>
    <help-text id="ZipCode.HelpText">
        Your ZIP code
    </help-text>
</question>

Anschließend muss die angepasste Funktion, die die Validierung durchführen soll, als Java-Klasse in dem Paket curam.rules.functions erstellt werden:

Abbildung 3. Angepasste Funktion zum Validieren der Postleitzahl
...
public class CustomFunctionValidateZipCode extends CustomFunctor {

  public Adaptor getAdaptorValue(final RulesParameters rp)
  throws AppException, InformationalException {

    final List<Adaptor> parameters = getParameters();
    final String zipCode =
      ((StringAdaptor) parameters.get(0)).getStringValue(rp);
    final String state =
      ((StringAdaptor) parameters.get(1)).getStringValue(rp);
    boolean valid = false;

    if (zipCode.length() == 5) {
      final String prefix = zipCode.substring(0, 3);
      //lookup the state prefixes
      if (prefix.equals("100")
        && state.equalsIgnoreCase("New York")) {
        valid = true;
      }
      if (prefix.equals("900")
        && state.equalsIgnoreCase("California")) {
        valid = true;
      }
    }

    return AdaptorFactory.getBooleanAdaptor(Boolean.valueOf(valid));
  }

}

In <yourcomponent>/rulesets/functions/CustomFunctionMetaData.xml müssen die folgenden Metadaten für die angepasste Funktion eingefügt werden:

Abbildung 4. Metadaten für eine angepasste Funktion
<CustomFunctor name="CustomFunctionValidateZipCode">
  <parameters>
    <parameter>
      curam.util.rules.functor.Adaptor$StringAdaptor
    </parameter>
    <parameter>
      curam.util.rules.functor.Adaptor$StringAdaptor
    </parameter>
  </parameters>
  <returns>curam.util.rules.functor.Adaptor$BooleanAdaptor</returns>
</CustomFunctor>

Weitere Informationen zum Definieren von angepassten Funktionen finden Sie im Handbuch Cúram Rules Codification Guide.

Im genannten Beispiel greift die angepasste Funktion "ValidateZipCode" nicht auf eine externe Datenbank zu, um den entsprechenden Bundesstaat zu suchen. Im Idealfall sollte sie diese Suche ausführen und anschließend den wiedergegebenen Bundesstaat mit der Angabe für den Bundesstaat vergleichen, die eingegeben wurde. Aus Gründen der Vereinfachung sind im obigen Beispiel nur zwei Postleitzahlenpräfixe fest codiert.

Die Validierung wird nun in die Seite mit den persönlichen Angaben eingefügt:

Abbildung 5. Validierung der Postleitzahl in der Scriptdefinition
<validation
  expression="ValidateZipCode(Person.zipCode, Person.state)">
    <message id="InvalidZipCode">
        The ZIP code is invalid.
    </message>
</validation>

Mit dem Klicken auf "Weiter" werden die Antworten auf die Fragen "zipCode" und "state" an die angepasste Funktion übergeben, die im Falle gültiger Antworten den Wert "true" zurückgibt. Anschließend wird die nächste Seite angezeigt.

Gibt die angepasste Funktion den Wert "false" zurück, wird die in der Validierung angegebene Nachricht am Anfang der Seite mit den persönlichen Angaben angezeigt und der Zugriff auf die nächste Seite so lange blockiert, bis gültige Antworten übergeben werden.

Da sie keine Veränderungen bewirkt, hat die angepasste Funktion keine Nebeneffekte. Sie führt lediglich anhand der Parameter eine Operation durch und gibt ein Ergebnis zurück.

Es besteht auch die Möglichkeit, die obligatorische Markierung für die zwei neuen Fragen zu entfernen und die Antworten nur dann zu validieren, wenn beide angegeben worden sind. In dem Fall müsste der Prüfausdruck mithilfe der sofort einsatzfähigen angepassten Funktion "isNotNull", die überprüft, ob der angegebene Parameter Null ist, folgendermaßen geändert werden:

Abbildung 6. Alternativer Prüfausdruck
"not(isNotNull(Person.zipCode) and isNotNull(Person.state))
    or ValidateZipCode(Person.zipCode, Person.state)"

Alternativ dazu besteht die Möglichkeit, die Frage "state" mit der angegebenen Postleitzahl zu füllen. Zu diesem Zweck wird auf der Seite mit den persönlichen Angaben nur nach "zipCode" (mit der obligatorischen Markierung) gefragt, und die Zusammenfassungsseite zeigt sowohl Bundesstaat als auch Postleitzahl an.

Folgende angepasste Funktion sollte definiert werden:

Abbildung 7. Angepasste Funktion zum Füllen des Felds "Bundesstaat"
...
public class CustomFunctionpopulateState extends CustomFunctor {

  public Adaptor getAdaptorValue(final RulesParameters rp)
  throws AppException, InformationalException {

    final IEG2Context ieg2Context = (IEG2Context) rp;
    final long rootEntityID = ieg2Context.getRootEntityID();
    String schemaName; 
    //schemaName has to be hard-coded or retrieved outside of IEG
    Datastore ds = null;
    try {
      ds =
        DatastoreFactory.newInstance().openDatastore(
            schemaName);
    } catch (NoSuchSchemaException e) {
      throw new AppException(IEG.ID_SCHEMA_NOT_FOUND);
    }

    Entity applicationEntity = ds.readEntity(rootEntityID);

    Entity personEntity =
      applicationEntity.getChildEntities(
        ds.getEntityType("Person"))[0];
    String zipCode = personEntity.getAttribute("zipCode");
    String state = "Unknown";
    final String prefix = zipCode.substring(0, 3);
    //lookup the state prefixes
    if (prefix.equals("100")) {
      state = "New York";
    }
    if (prefix.equals("900")) {
      state = "California";
    }
    personEntity.setAttribute("state", state);
    personEntity.update();
    return AdaptorFactory.getBooleanAdaptor(new Boolean(true));
  }

}

Dazu die Metadaten:

Abbildung 8. Metadaten der angepassten Funktion
<CustomFunctor name="CustomFunctionpopulateState">
  <returns>curam.util.rules.functor.Adaptor$BooleanAdaptor</returns>
</CustomFunctor>

Zwischen der Seite mit den persönlichen Angaben und der Zusammenfassungsseite muss ein Aufrufelement eingefügt werden, das diese angepasste Funktion aufruft:

Abbildung 9. Aufruf zum Füllen des Felds "Bundesstaat" in der Scriptdefinition
<callout id="populateAddress" expression="populateState()"/>

In diesem Fall bewirkt die angepasste Funktion eine Veränderung im DS, indem sie das Feld "Bundesstaat" zur Personenentität füllt. Der Kontext enthält die Stammebenen-Entitäts-ID und die Ausführungs-ID, wodurch das Aktualisieren des DS erleichtert wird. Befindet sich der Aufruf in einer Schleife, enthält der Kontext ebenfalls die aktuelle Entitäts-ID.