Call Activity

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

BPMN 2.0 различает встроенный подпроцесс и операцию вызова. С концептуальной точки зрения, обе они вызывают подпроцесс, когда исполнение процесса достигает соответствующей активности.

Различие в том, что операция вызова ссылается на процесс, внешний по отношению к определению процесса, тогда как подпроцесс встроен в исходное определение процесса. Основной сценарий использования операции вызова — иметь переиспользуемое определение процесса, которое может быть вызвано из множества других определений процессов. Хотя это пока не входит в спецификацию BPMN, также возможно вызвать определение CMMN-кейса.

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

call activity

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

Операция вызова — это обычная активность, требующая атрибута calledElement, который ссылается на определение процесса по его ключу. На практике это означает, что в calledElement используется id процесса:

<callActivity id="callCheckCreditProcess" name="Check credit" calledElement="checkCreditProcess" />

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

Привязка CalledElement

В операции вызова атрибут calledElement содержит ключ определения процесса как ссылку на подпроцесс. Это означает, что всегда вызывается последняя версия определения процесса подпроцесса. Чтобы вызвать другую версию подпроцесса, в операции вызова можно задать атрибуты calledElementBinding, calledElementVersion и calledElementVersionTag. Эти атрибуты являются необязательными.

CalledElementBinding имеет четыре различных значения:

  • latest: всегда вызывать последнюю версию определения процесса (это также поведение по умолчанию, если атрибут не задан)

  • deployment: если вызываемое определение процесса входит в тот же деплоймент, что и вызывающее определение процесса, использовать версию из деплоймента

  • version: вызвать фиксированную версию определения процесса, в этом случае требуется calledElementVersion. Номер версии может быть либо указан в BPMN XML, либо возвращён выражением (см. пользовательские расширения)

  • versionTag: вызвать фиксированный тег версии определения процесса, в этом случае требуется calledElementVersionTag. Тег версии может быть либо указан в BPMN XML, либо возвращён выражением (см. пользовательские расширения)

<callActivity id="callSubProcess" calledElement="checkCreditProcess"
  camunda:calledElementBinding="latest|deployment|version"
  camunda:calledElementVersion="17">
</callActivity>

or

<callActivity id="callSubProcess" calledElement="checkCreditProcess"
  camunda:calledElementBinding="versionTag"
  camunda:calledElementVersionTag="ver-tag-1.0.1">
</callActivity>

Tenant Id операции CalledElement

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

Разрешение арендатора по умолчанию

По умолчанию для разрешения вызываемого определения процесса используется tenant id вызывающего определения процесса. То есть, если у вызывающего определения процесса нет tenant id, то операция вызова разрешает определение процесса по предоставленному ключу, привязке и без tenant id (tenant id = null). Если у вызывающего определения процесса есть tenant id, разрешается определение процесса с предоставленным ключом и тем же tenant id.

Обратите внимание, что tenant id вызывающего экземпляра процесса в поведении по умолчанию не учитывается.

Явное разрешение арендатора

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

Атрибут camunda:calledElementTenantId позволяет явно указать tenant id:

<callActivity id="callSubProcess" calledElement="checkCreditProcess"
  camunda:calledElementTenantId="TENANT_1">
</callActivity>

Если tenant id неизвестен на этапе проектирования, также можно использовать выражение:

<callActivity id="callSubProcess" calledElement="checkCreditProcess"
  camunda:calledElementTenantId="${ myBean.calculateTenantId(variable) }">
</callActivity>

Выражение также позволяет использовать tenant id вызывающего экземпляра процесса вместо вызывающего определения процесса:

<callActivity id="callSubProcess" calledElement="checkCreditProcess"
  camunda:calledElementTenantId="${ execution.tenantId }">
</callActivity>

Передача переменных

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

<callActivity id="callSubProcess" calledElement="checkCreditProcess" >
  <extensionElements>
    <camunda:in source="someVariableInMainProcess" target="nameOfVariableInSubProcess" />
    <camunda:out source="someVariableInSubProcss" target="nameOfVariableInMainProcess" />
  </extensionElements>
</callActivity>

По умолчанию переменные, объявленные в элементах out, устанавливаются в максимально высокой области видимости переменных.

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

<callActivity id="callSubProcess" calledElement="checkCreditProcess" >
  <extensionElements>
    <camunda:in variables="all" />
    <camunda:out variables="all" />
  </extensionElements>
</callActivity>

Здесь также можно использовать выражения:

<callActivity id="callSubProcess" calledElement="checkCreditProcess" >
  <extensionElements>
    <camunda:in sourceExpression="${x+5}" target="y" />
    <camunda:out sourceExpression="${y+5}" target="z" />
  </extensionElements>
</callActivity>

Таким образом, в итоге выполняется равенство z = y+5 = x+5+5.

Исходные выражения вычисляются в контексте вызываемого экземпляра процесса. Это означает, что в случаях, когда вызывающее и вызываемое определения процессов принадлежат разным приложениям процессов, контекст вроде Java-классов, Spring- или CDI-бинов разрешается из того приложения процесса, которому принадлежит вызываемое определение процесса.

Вывод переменных при событии BPMN Error Event

Когда событие BPMN Error Event из вызываемого экземпляра процесса ловится в вызывающем экземпляре процесса, также выполняются маппинги выходных переменных. В зависимости от моделей BPMN это требует, чтобы выходные параметры допускали значения null для переменных, которые не существуют в вызываемом экземпляре в момент распространения ошибки.

Сочетание с параметрами Input/Output

Операции вызова также можно сочетать с параметрами Input/Output. Это позволяет ещё более гибко маппить переменные в вызываемый процесс. Чтобы маппить только переменные, объявленные в маппинге inputOutput, можно использовать атрибут local. Рассмотрим следующий XML:

<callActivity id="callSubProcess" calledElement="checkCreditProcess" >
  <extensionElements>
    <!-- Input/Output parameters -->
    <camunda:inputOutput>
      <camunda:inputParameter name="var1">
        <camunda:script scriptFormat="groovy">
          <![CDATA[
            sum = a + b + c
          ]]>
        </camunda:script>
      </camunda:inputParameter>
      <camunda:inputParameter name="var2"></camunda:inputParameter>
    </camunda:inputOutput>

    <!-- Mapping to called instance -->
    <camunda:in variables="all" local="true" />
  </extensionElements>
</callActivity>

Установка local="true" означает, что все локальные переменные исполнения, выполняющего операцию вызова, маппятся в вызываемый экземпляр процесса. Это в точности те переменные, которые объявлены как входные параметры.

То же самое можно сделать с выходными параметрами:

<callActivity id="callSubProcess" calledElement="checkCreditProcess" >
  <extensionElements>
    <!-- Input/Output parameters -->
    <camunda:inputOutput>
      <camunda:outputParameter name="var1">
        <camunda:script scriptFormat="groovy">
          <![CDATA[
            sum = a + b + c
          ]]>
        </camunda:script>
      </camunda:outputParameter>
      <camunda:outputParameter name="var2"></camunda:outputParameter>
    </camunda:inputOutput>

    <!-- Mapping from called instance -->
    <camunda:out variables="all" local="true" />
  </extensionElements>
</callActivity>

Когда вызываемый экземпляр процесса завершается, из-за local="true" в параметре camunda:out все переменные маппятся в локальные переменные исполнения, выполняющего операцию вызова. Эти переменные можно смаппить в переменные экземпляра процесса с помощью выходного маппинга. Любая переменная, не объявленная элементом camunda:outputParameter, после завершения операции вызова станет недоступна.

Делегирование маппинга переменных

Маппинг входных и выходных переменных также можно делегировать. Это означает, что передача входных и/или выходных переменных может выполняться в Java-коде. Для этого должен быть реализован интерфейс Delegate Variable Mapping.

Есть два возможных способа использовать делегирование для маппинга переменных.

Делегирование маппинга переменных через ссылку

Первый — задать свойство расширения Camunda variableMappingClass и сослаться на реализацию интерфейса DelegateVariableMapping через полное имя класса.

 <process id="callSimpleSubProcess">

    <startEvent id="theStart" />

    <sequenceFlow id="flow1" sourceRef="theStart" targetRef="callSubProcess" />

    <callActivity id="callSubProcess" calledElement="simpleSubProcess" camunda:variableMappingClass="io.openbpm.bpm.example.bpm.callactivity.DelegatedVarMapping"/>

    <sequenceFlow id="flow3" sourceRef="callSubProcess" targetRef="taskAfterSubProcess" />

    <userTask id="taskAfterSubProcess" name="Task after subprocess" />

    <sequenceFlow id="flow4" sourceRef="taskAfterSubProcess" targetRef="theEnd" />

    <endEvent id="theEnd" />

  </process>

Делегирование маппинга переменных через выражение

Второй — задать свойство расширения Camunda variableMappingDelegateExpression с выражением. Это позволяет указать выражение, которое разрешается в объект, реализующий интерфейс DelegateVariableMapping.

  <process id="callSimpleSubProcess">

    <startEvent id="theStart" />

    <sequenceFlow id="flow1" sourceRef="theStart" targetRef="callSubProcess" />

    <callActivity id="callSubProcess" calledElement="simpleSubProcess" camunda:variableMappingDelegateExpression="${expr}"/>

    <sequenceFlow id="flow3" sourceRef="callSubProcess" targetRef="taskAfterSubProcess" />

    <userTask id="taskAfterSubProcess" name="Task after subprocess" />

    <sequenceFlow id="flow4" sourceRef="taskAfterSubProcess" targetRef="theEnd" />

    <endEvent id="theEnd" />

  </process>

См. Delegate Variable Mapping для дополнительной информации о реализации интерфейса.

Передача бизнес-ключа

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

<callActivity id="callSubProcess" calledElement="checkCreditProcess" >
  <extensionElements>
    <camunda:in businessKey="#{execution.processBusinessKey}" />
  </extensionElements>
</callActivity>

Пример

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

call activity

XML выглядит следующим образом:

<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="shipping" />

<callActivity id="shipping" name="Shipping" calledElement="shippingProcess" />
<sequenceFlow id="flow2" sourceRef="shipping" targetRef="billing" />

<callActivity id="billing" name="Billing" calledElement="billingProcess" />
<sequenceFlow id="flow3" sourceRef="billing" targetRef="end" />

<endEvent id="end" />

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

Создание экземпляра кейса

Операция вызова также может использоваться для создания нового экземпляра CMMN-кейса как подчинённого по отношению к соответствующему экземпляру процесса. Операция вызова завершается, как только созданный экземпляр кейса впервые достигает состояния COMPLETED. В отличие от вызова BPMN-процесса, для ссылки на определение кейса по его ключу вместо атрибута calledElement должен использоваться атрибут caseRef. Это означает, что всегда вызывается последняя версия определения кейса.

Привязка кейса

Чтобы вызвать другую версию определения кейса, в операции вызова можно задать атрибуты caseBinding и caseVersion. Оба атрибута являются необязательными.

CaseBinding имеет три различных значения:

  • latest: всегда вызывать последнюю версию определения кейса (это также поведение по умолчанию, если атрибут не задан)

  • deployment: если вызываемое определение кейса входит в тот же деплоймент, что и вызывающее определение процесса, использовать версию из деплоймента

  • version: вызвать фиксированную версию определения кейса, в этом случае требуется caseVersion

<callActivity id="callSubProcess" camunda:caseRef="checkCreditCase"
  camunda:caseBinding="latest|deployment|version"
  camunda:caseVersion="17">
</callActivity>

Tenant Id кейса

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

Поведение по умолчанию #_default_tenant_resolution такое же, как при разрешении определений BPMN-процессов (то есть для разрешения вызываемого определения кейса используется tenant id вызывающего определения процесса).

Чтобы переопределить поведение по умолчанию, tenant id для разрешения вызываемого определения кейса можно указать явно с помощью атрибута camunda:caseTenantId:

<callActivity id="callSubProcess" camunda:caseRef="checkCreditCase"
  camunda:caseTenantId="TENANT_1">
</callActivity>

Если tenant id неизвестен на этапе проектирования, также можно использовать выражение:

<callActivity id="callSubProcess" camunda:caseRef="checkCreditCase"
  camunda:caseTenantId="${ myBean.calculateTenantId(variable) }">
</callActivity>

Выражение также позволяет использовать tenant id вызывающего экземпляра процесса вместо вызывающего определения процесса:

<callActivity id="callSubProcess" camunda:caseRef="checkCreditCase"
  camunda:caseTenantId="${ execution.tenantId }">
</callActivity>

Расширения Camunda

Атрибуты

Элементы расширения

Ограничения

Атрибут camunda:exclusive учитывается только если атрибут camunda:asyncBefore или camunda:asyncAfter установлен в true

Атрибут camunda:calledElementVersion следует задавать только если атрибут camunda:calledElementBinding равен version

Атрибут calledElement не может использоваться в сочетании с атрибутом camunda:caseRef и наоборот.

Атрибут camunda:caseVersion следует задавать только если атрибут camunda:caseBinding равен version

Дополнительные ресурсы

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

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

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