Вызов решений из процессов и сценариев

Этот раздел перенесён из документации Camunda 7 и в дальнейшем будет доработан с учётом особенностей OpenBPM Engine

Интеграция BPMN и CMMN

Этот раздел объясняет, как вызывать DMN решения из BPMN и CMMN.

BPMN задача с бизнес-правилом

BPMN задача с бизнес-правилом может ссылаться на определение can reference a задеплоенного решения. Определение решения оценивается при выполнении задачи.

<definitions id="taskAssigneeExample"
  xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
  xmlns:camunda="http://camunda.org/schema/1.0/bpmn"
  targetNamespace="Examples">

  <process id="process">

    <!-- ... -->

    <businessRuleTask id="businessRuleTask"
                      camunda:decisionRef="myDecision"
                      camunda:mapDecisionResult="singleEntry"
                      camunda:resultVariable="result" />

    <!-- ... -->

  </process>
</definitions>

Чтобы получить больше информации о том, как ссылаться на определение решения из задачи с бизнес-правилом, см. Справочник по BPMN 2.0.

Задача с DMN решением

Задача с DMN решением ссылается на определение задеплоенного решения. Определение решения вызывается, когда задача активирована.

<definitions id="definitions"
                  xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL"
                  xmlns:camunda="http://camunda.org/schema/1.0/cmmn"
                  targetNamespace="Examples">
  <case id="case">
    <casePlanModel id="CasePlanModel_1">
      <planItem id="PI_DecisionTask_1" definitionRef="DecisionTask_1" />
      <decisionTask id="DecisionTask_1"
                    decisionRef="myDecision"
                    camunda:mapDecisionResult="singleEntry"
                    camunda:resultVariable="result">
      </decisionTask>
    </casePlanModel>
  </case>
</definitions>

Чтобы получить больше информации о том, как ссылаться на определени решения из завачи с решением, см. Справочник по CMMN 1.1.

Результат решения

Выходные данные от решения, также называемые результатом решения, являются комплексным объектом типа DmnDecisionResult. Обычно это список пар ключ-решение.

Если решение реализовано как таблица решений, тогда кажде вхождение в списке представляет собой одно выполненное правило. Элементы выходных данных для этого правила представлены как пары ключ-значение. Ключ в такой паре задается через имя выходных данных.

Если же, напротив, решение реализовано как литеральное выражегние решения, тогда список содержит только одно вхождение. Оно представляет собой значение выражения и получает маппинг на имя переменной.

Тип DmnDecisionResult предоставлет методы из интерфейса List и некоторые методы для удобства, например getSingleResult() или getFirstResult(), чтобы получить результат выполненного правила. Результаты правила предоставляют методы из интерфейса Map и методы для удобства, например, getSingleEntry() или getFirstEntry().

Если результат решения содержит только одно выходное значение(например, при оценке литерального выражения решения), тогда это значение можно извлечь из результата, используя метод getSingleEntry(), который сочетает в себе getSingleResult() и getSingleEntry().

Например, следующий код возвращает элемент выходных данных с именем result от единственного выполненного правила.

DmnDecisionResult decisionResult = ...;

Object value = decisionResult
  .getSingleResult()
  .getEntry("result");

Он также предоставляет метод для получения типизированных элементов выходных данных, а именно getSingleEntryTyped(). См. Руководство пользователя, чтобы узнать больше о типизированных значениях. Полный список всех методов можно найти в Java Docs.

Результат решения доступен в локальном скоупе выполняющейся задачи как транзиентная переменная с именем decisionResult. Он может передаваться в переменную с использованием предварительно заданного кастомного маппинга результата решения, если это необходимо.

Предварительно заданный маппинг результата решения

Движок включает предварительно заданные маппинги результатов решения для распространенных сценариев использования. Этот маппинг похож на маппинг выходных переменных . Он извлекает значение из результата решения, которое сохраняется в переменной процесса/сценария. Доступны следующие маппинги:

Маппер Результат Подходит для

singleEntry

TypedValue

литеральных выражений решений и таблиц решений, в которых есть только одно выполняемое правило и только один элемент выходных данных

singleResult

Map<String, Object>

таблиц решений с не более чем одним выполняемым правилом

collectEntries

List<Object>

таблиц решений с несколькими выполняемыми правилами, но только одним элементом выходных данных

resultList

List<Map<String, Object>>

таблиц решений с несколькими выполняемыми правилами и несколькими элементами выходных данных

Только маппер singleEntry возвращает типизированное значение, которое оборачивает значение элемента выходных данных и дополнительную игформацию о типе. Остальные мапперы возвращают коллекции, которые содержат значения элементов выходных данных как нормальные Java-объекты без дополнительной информации о типе.

Обратите внимание, что маппер выбрасывает исключение, если результат решения не подходит. Например, маппер singleEntry выбрасывает исключение, если результат решения содержит более одного выполненного правила.

Если вы используете один из предварительно заданных мапперов: singleResult, collectEntries или`resultList`, тогда вам следует рассмотреть ограничения сериализации.

Чтобы задать имя переменной процесса/сценария для хранения результата маппинга, используется атрибут camunda:resultVariable.

BPMN:

<businessRuleTask id="businessRuleTask"
                  camunda:decisionRef="myDecision"
                  camunda:mapDecisionResult="singleEntry"
                  camunda:resultVariable="result" />

CMMN:

<decisionTask id="DecisionTask_1"
              decisionRef="myDecision"
              camunda:mapDecisionResult="singleEntry"
              camunda:resultVariable="result">

Переменная результата не должна называться decisionResult, поскольку сам результат решения сохраняется в переменную с таким именем. Иначе будет выброшено исключение при попытке сохранить переменную результата.

Кастомный маппинг результата решения

Вместо предварительно заданного маппинга для передачи результата решения в переменные можно использовать кастомный маппинг результата решения.

Если вы передаете коллекцию комплексных объектов в переменную, вам следует рассмотреть возможность ограничения сериализации.

Кастомный маппинг на процессные переменные

Если задача с бизнес-правилом используется для вызова решения внутри BPMN процесса, то результат решения может передаваться в переменные процесса с использованием маппинга выходных переменных.

Например, если результат решения именнт несколько выходных значений, которые должны мохраняться в отдельных процессных переменных, этого можно достичь через определение выходного маппинга на задачу с бизнес-правилом.

<businessRuleTask id="businessRuleTask" camunda:decisionRef="myDecision">
  <extensionElements>
    <camunda:inputOutput>
      <camunda:outputParameter name="result">
        ${decisionResult.getSingleResult().result}
      </camunda:outputParameter>
      <camunda:outputParameter name="reason">
        ${decisionResult.getSingleResult().reason}
      </camunda:outputParameter>
    </camunda:inputOutput>
  </extensionElements>
</businessRuleTask>

В дополнение к маппингу выходной переменной, результат решения может также быть обработан через слушатель выполнений, которые прикреплен к задаче с бизнес-правилом.

<businessRuleTask id="businessRuleTask" camunda:decisionRef="myDecision">
  <extensionElements>
    <camunda:executionListener event="end"
      delegateExpression="${myDecisionResultListener}" />
  </extensionElements>
</businessRuleTask>
public class MyDecisionResultListener implements ExecutionListener {

  @Override
  public void notify(DelegateExecution execution) throws Exception {
    DmnDecisionResult decisionResult = (DmnDecisionResult) execution.getVariable("decisionResult");
    String result = decisionResult.getSingleResult().get("result");
    String reason = decisionResult.getSingleResult().get("reason");
    // ...
  }

}

Кастомный маппинг на переменные сценария

Если задача с решением используется для вызова решения внутри CMMN сценария, результат решения может передаваться в переменную сценария с использованием слушателя выполнения сценария, прикрепленного к задаче с решением.

<decisionTask id="decisionTask" decisionRef="myDecision">
  <extensionElements>
    <camunda:caseExecutionListener event="complete"
      class="io.openbpm.bpm.example.MyDecisionResultListener" />
  </extensionElements>
</decisionTask>
public class MyDecisionResultListener implements CaseExecutionListener {

  @Override
  public void notify(DelegateCaseExecution caseExecution) throws Exception;
    DmnDecisionResult decisionResult = (DmnDecisionResult) caseExecution.getVariable("decisionResult");
    String result = decisionResult.getSingleResult().get("result");
    String reason = decisionResult.getSingleResult().get("reason");
    // ...
    caseExecution.setVariable("result", result);
    // ...
  }

}

Ограничения, налагаемые на сериализацию результатов маппинга

Предварительно определенные маппинга singleResult, collectEntries и resultList соотносят результаты решений с Java коллекциями. Реализация коллекций зависит от используемого JDK и содержит нетипизированные значения, представленные как тип Object. Когда коллекция является переменной процесса/сценария, она сериализуется как объект, поскольку подходящего примитивного типа значения не существует. В зависимости от используемой сериализации значения объекта, это может привести к проблемам при десериализации.

В случае, если вы используете встроенную сериализацию для объектов по умолчанию, переменная не может быть десериализована, если обновить или изменить JDK на другой, содержащий несовместимую версию класса коллекции. В противном случае, если вы используете другую сериализацию, например, JSON, то вам необходимо удостовериться в том, что нетипизированное значение подходит для десериализации. Например, коллекция значений дат не может быть десериализована с использованием JSON, поскольку JSON не имеет зарегистрированного маппера для дат по умолчанию.

Такие же проблемы могут возникнуть при использовании маппинга для кастомной выходной переменной, поскольку DmnDecisionResult содержит методы, которые возвращают те же коллекции, что и предопределенные маппинги. Кроме того, не рекомендуется сохранять DmnDecisionResult или DmnDecisionResultEntries как переменную процесса/сценария, потому что внутренняя реализация может измениться в новой версии Camunda 7.

Чтобы предотарвтить появление всех этих проблем, вам следует использовать только примитивные переменные. В качестве альтернативы вы можете использовать кастомный объект для сериализации, которую вы полностью контролируете сами.

Оценка переменных из решений

Таблицы решений и литеральные выражения решений в DMN содержат по нескольку выражений, которые могут быть оценены DMN движком. Чтобы узнать больше о выражениях в решении, см. наш справочник по DMN 1.3. Эти выражения могут получать доступ ко всем переменным процессов/сценариев, которые доступны внутри области видимости вызывающей задачи. Переменные предоставляются через read-only контекст переменной.

В качестве короткого варианта, на переменные процесса/сценария можно ссылаться напрямую по имени в выражении. Например, если существует процессная переменная foo, эта переменная может использоваться во входном выражении, в элементах входных и выходных данных внутри таблицы решения, и на нее можно ссылаться по ее имени.

<input id="input">
  <!--
    this input expression will return the value
    of the process/case variable `foo`
  -->
  <inputExpression>
    <text>foo</text>
  </inputExpression>
</input>

Возвращаемое значение переменной процесса/сценария внутри выражения будет нормальным объектом, а не типизированным значением. Если вы хотите использовать в ваших выражениях типизированные значения, вам придется взять переменную из контекста переменной. Следующий фрагмент кода делает то же самое, что и пример выше. Он берет переменную foo из контекста переменной и возвращает ее необернутое значение.

<input id="input">
  <!--
    this input expression uses the variable context to
    get the typed value of the process/case variable `foo`
  -->
  <inputExpression>
    <text>
      variableContext.resolve("foo").getValue()
    </text>
  </inputExpression>
</input>

Интеграция языка выражений

By default, the DMN engine uses FEEL as expression language for input expressions, input entries, output entries and literal expressions. Please see the DMN engine guide for more information about expression languages.

Accessing Beans

If the DMN engine is invoked by Camunda 7, it uses the same JUEL configuration as the Camunda 7 engine. Therefore, it is also possible to access Spring and CDI Beans from JUEL expressions in decisions. For more information on this integration, please see the corresponding section in the Spring and CDI guides.

[NOTE, caption=Осторожно!]: Beans cannot be accessed when using FEEL as expression language.

Extending the Expression Language

ИСПОЛЬЗОВАНИЕ ВНЕШНЕГО API:

Эти API не являются частью публичного API и могут поменяться в более поздних релизах.

Вы можете добавить свои собственные функции, которые можно использовать внутри JUEL-выражений. Следовательно, необходимо реализовать новый {{< javadocref page="?org/camunda/bpm/engine/impl/javax/el/FunctionMapper.html" text="FunctionMapper" >}}. Маппер функции должен затем быть добавлен к конфигурации движка управления процессами после своей инициализации.

ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) processEngine
  .getProcessEngineConfiguration();

processEngineConfiguration
  .getExpressionManager()
  .addFunctionMapper(new MyFunctionMapper());

Это можно сделать, например, посредством создания плагина движка управления процессами.

Обратите внимание, что эти функции доступны во всех JUEL выражениях внутри платформы, не только в DMN решениях.

Лицензия и атрибуция

Эта документация была создана на базе материала "Camunda 7 Docs" от Camunda, находится под лицензией Creative Commons Attribution-ShareAlike 3.0 Unported License .

Оригинал документации: https://docs.camunda.org