LSPS documentation logo
LSPS Documentation
Decision Tables

Decision tables serve to define business rules, which are then used to adapt the behavior of models. The tables can be modified on runtime.

Note: The LSPS implementation of Decision Model and Notation (DMN) is based on the industry standard for decisions established by OMG, DMN version 1.1.

Decision tables are defined in a dedicated editor in Designer as part of a module. The module can then evaluate a rule on runtime and be designed to behave differently depending on the rule outcome.

A decision table is considered a shared record. To evaluate a rule use the evaluation() call with the input expressions on the record: The call checks which input entries fit the table input values and returns their output values.

A decision table can be modified by users from their process application in their browser: They are made available by the Decision Table components in form definitions.

decisionTables_description.png
The evaluation call to the decision table takes the trainer and level arguments and returns the trainingDays value.

Designing a Decision Table

To design a decision table, do the following:

  1. Import the dmn module with the decision-tables-related resources.
  2. Create a decision-table definition file: right-click the module and go to New -> Decision Table Definition, enter the decision table name, for example, TrainingDays.
  3. Select the language of the rules:
    1. Click the cell with the value LSPS.
    2. In the context menu, select the language:
      • LSPS: you will specify the input values as full Boolean expressions or as the right side of Boolean expressions with an operator, for example, < 1000, in 1..1000
      • SFEEL: though simple, the language is very restrictive; refer to the SFEEL section for further information.
  4. Define the input parameters as blue columns:

    1. Add or remove the columns to match the number of input parameters: click the ::: icon in the title of a blue column and in the context menu, select the required action.
      decisionTables_addingInput.png
      Adding input column
    2. In each column header, define the properties of the input parameter:
      • Define the label of the input in the top cell of the column header
      • Define the data type of the input in the cell below (If undefined, it is considered an Object).
      • Optionally in the cell bellow the data type, define the allowed input values: click the Edit Allowed Values button and use the displayed dialog.
        editAllowedValuesInDecisionTables.png
        You can use the input expressions, that is, the column captions, to reference the values passed to the decision table, for example, if an input column has the name income you can use it in an expression, such as, getIncomeInEur(income) > 1000.

    Note that while output columns can make use of input columns, input columns cannot see the output columns.

  5. If you require special handling on a rule, or you need to prepare additional data for the output, define an input with no name. Note that such inputs are not considered inputs and are not set by an input argument.
    anonymousinput.png
    Handling a special case in first rule using anonymous input
  6. Define the result outputs as red columns:
    1. Add or remove the columns to match the number of output values: click the ::: icon in the label cell of a red column and in the context menu, select the required action.
    2. In each column header, define the properties of the output parameter:
      • Define the label of the output in the top cell of the column header
      • Define the data type of the output in the cell below (If undefined, it is considered Object).
      • Optionally in the cell bellow the data type, define the allowed output values: click the Edit Allowed Values button and use the displayed dialog.
  7. Click the policy cell to set the hit policy:
    • FIRST: the output of the first satisfied condition set is returned as the result.

      The return value is one instance of the outputs.

    • RULE_ORDER: the outputs of all satisfied conditions are returned as a list; the order of the outputs follows the order, in which the rules are defined.
      dt_settingHitPolicy.png
  8. Define the rules: click the + sign to add a row for a new rule to the table and define the input conditions that must be true for the rule to apply and their output values.
  9. To manage the rules, select and right-click the number in the rule row and select the required action; you can copy and paste a rule, remove a rule, change the order of rules, etc.
    copyingRule.png
    You can design the decision tables also programmatically with the API methods, such as, setHitPolicy(), addInput(), addOutput(), addRules(), and others. Refer to the dmn documentation.

Now you can use the decision table in your model to evaluate a rule and add it to a form so it can be edited from the Process Application.

To check the constructor and methods of the decision table, including the evaluate() method which you call on a decision table with input arguments to get the output value, right-click below the table and select Display Methods.

decisionTables_displayMethods.png

SFEEL

SFEEL is a simple expression language in which you can define the business rules in a decision table. However, mind that the rules must not have any side effects; they can use only basic data types and simple unary conditions with no external resources. If you require more complex expressions in your decision table, use the LSPS Expression Language.

Even if you set your decision table to use SFEEL, the input and output data types on decision tables are defined as their LSPS equivalents:

Original SFEEL LSPS SFEEL Example
boolean Boolean true, false
number Decimal or Integer 11.0001, 12
string String "hello"
days and time duration duration(string_literal) duration("P2DT3H4M30.1S")
year and months duration duration(string_literal) duration("P1Y10M")
time time(string_literal) time("10:00")
date date(string_literal) date("2012-12-24"), date("2012-12-24+09:00")

Merging and Splitting Cells

To merge a cell with the cell below in your decision table, right-click the cell and select Merge Cells. You can split a merged cell into the individual cell analogously: select Split Cells from the context menu.

decisionTablesMergingCells.png

Copying Rules

To copy a rule in your decision table, click its row number and select Copy Rule. To paste it, click the row number of the row under which you want to insert the rule and select Paste Rule.

decisionrulecopy.png

Creating, Saving and Loading a Decision Table

You can create a new decision table instance with the constructor with the argument true: <Constructor>(true) will construct the table based on the definition.

If you want to use the same decision table on multiple occasions, for example, from different process instances, you can persist it and load it later.

You can save a decision table with the save(<StringID>) method of the decision-table instance. To load a decision table, create its uninitialized instance and then call the load(<StringID>) method on it.

  • <Constructor>(false) will only create the decision table without values so you can load a saved table into it using the load() call. Example loading of a decision table if it exists
    def ApplicationTrainingDays atd := new ApplicationTrainingDays(false);
    //create a table with the TrainingDaysTable id if it does not exist in the db:
    if (atd.load("TrainingDaysTable") == false) then
    atd := new ApplicationTrainingDays(true);
    atd.save("TrainingDaysTable")
    end;

These calls enable you to save and load a decision table from the Process Application via the Decision Table component. Note that you can change the decision table definition in the component as well.

To find a saved table, call findDecisionTableIds(<IdPattern>) or findDecisionTables(<IdPattern>).

Note: You will not be able to check the return type of an evaluate() call on design time for tables acquired with the load() method call since the tables could be edited on runtime and their input and output parameters might change.

You can check the logic in the methods of the decision table (right-click below the table and select Display Methods).

Evaluating a Rule with a Decision Table

When you want to make a decision based on the rules of a decision table, perform an evaluate() call on an instance of the table; to obtain a decision table, you can either create a new instance of the table or load a previously persisted table with the save() call. The evaluate() call evaluates the input conditions of the rules as defined in the table and returns one or multiple results in which all conditions are true or null; Mind that the number of results, that is, whether results only from one row or all matching rows is returned, depends on the hit policy setting.

To evaluate a rule in a new instance of a decision table, create the instance and call evaluate() on it. Note that in this scenario, the data types returned by the table are explicitly stated:

  • Table with the FIRST hit policy returns an instance of the output(s) or null if there are no matches.
    def TrainingDaysDT trainingDay := new TrainingDaysDT(true);
    //the type of return value depends on how you define the input parameters;
    //input parameters are defined as position parameters, return value is a list of the given type:
    def List<TrainingDays> ltd;
    ltd := trainingDay.evaluate(Trainer.MIKE, Level.INTERMEDIATE);
    //input parameters are defined as a map, return value is a list of map of objects of the given type:
    def List<Map<String,Object>> mtd;
    mtd := trainingDay.evaluate(["trainer" -> Trainer.MIKE, "level" -> Level.INTERMEDIATE]);
  • Table with the RULE_ORDER hit policy returns a List or Map of outputs (empty map if there are no matches):
    def TrainingDaysDT trainingDay := new TrainingDaysDT(true);
    def List<List<TrainingDays>> ltd;
    ltd := trainingDay.evaluate(Trainer.MIKE, Level.INTERMEDIATE);
    //or:
    def List<Map<String,Object>> mtd;
    mtd := trainingDay.evaluate(["trainer" -> Trainer.MIKE, "level" -> Level.INTERMEDIATE]);

Important: Designer and the LSPS Server do not check the type of the decision table: hence, if a variable is of a type of a particular DecisionTable and you assign it another type, it does not cause any exception. This allows editing of the DecisionTable structure on runtime from the Process Application.