Переменные процесса
|
Этот раздел перенесён из документации Camunda 7 и в дальнейшем будет доработан с учётом особенностей OpenBPM Engine |
В этом разделе описываются концепции переменных в процессах. Переменные могут использоваться для добавления данных в runtime-состояние процесса или, более конкретно, в области видимости переменных (variable scopes). Различные методы API, изменяющие состояние этих сущностей, позволяют обновлять связанные с ними переменные. В общем случае переменная состоит из имени и значения. Имя используется для идентификации в рамках конструкций процесса. Например, если одна активность устанавливает переменную с именем var, последующая активность может получить к ней доступ, используя это имя. Значение переменной — это Java-объект.
Области видимости переменных и видимость переменных (Variable Scopes and Variable Visibility)
Все сущности, которые могут иметь переменные, называются областями видимости переменных (variable scopes). Это executions (включая экземпляры процесса) и задачи (tasks). Как описано в разделе Concepts, runtime-состояние экземпляра процесса представлено деревом executions. Рассмотрим следующую модель процесса, где красные точки обозначают активные задачи:

Runtime-структура этого процесса выглядит так:

Существует экземпляр процесса с двумя дочерними execution, каждый из которых создал задачу. Все эти пять сущностей являются областями видимости переменных, а стрелки обозначают отношения родитель–потомок. Переменная, определённая в родительской области, доступна в каждой дочерней области, если только дочерняя область не определяет переменную с тем же именем. В обратную сторону это не работает: переменные дочерней области недоступны из родительской области. Переменные, которые прикреплены непосредственно к рассматриваемой области, называются локальными (local) переменными. Рассмотрим следующее назначение переменных областям видимости:

В этом случае при работе с Task 1 доступны переменные worker и customer. Обратите внимание, что из‑за структуры областей переменная worker может быть определена дважды, так что Task 1 обращается к другой переменной worker, чем Task 2. Однако обе задачи разделяют переменную customer, что означает: если эта переменная будет обновлена одной из задач, это изменение будет также видно и другой задаче.
Обе задачи могут получать доступ к двум переменным каждая, при этом ни одна из них не является локальной переменной. Все три execution имеют по одной локальной переменной.
Теперь предположим, что мы устанавливаем локальную переменную customer на Task 1:

Хотя из Task 1 по‑прежнему доступны две переменные с именами customer и worker, переменная customer на Execution 1 становится скрытой, поэтому доступная переменная customer — это локальная переменная Task 1.
В общем случае переменные доступны в следующих ситуациях:
-
При инстанцировании процессов
-
При доставке сообщений
-
При переходах жизненного цикла задач, таких как завершение (completion) или разрешение (resolution)
-
При установке/получении переменных извне
-
При установке/получении переменных в Delegate
-
В выражениях (expressions) в модели процесса
-
В скриптах в модели процесса
-
В запросах переменных (включая исторические)
Установка и получение переменных — обзор (Set and Retrieve Variables - Overview)
Для установки и получения переменных process engine предоставляет Java API, который позволяет задавать переменные из Java-объектов и получать их в том же виде. Внутри движок сохраняет переменные в базу данных и поэтому применяет сериализацию. Для большинства приложений это несущественная деталь. Однако иногда при работе с пользовательскими Java-классами представляет интерес сериализованное значение переменной. Представьте приложение мониторинга, которое управляет многими process applications. Оно отделено (decoupled) от классов этих приложений и поэтому не может получить доступ к пользовательским переменным в их Java‑представлении. Для таких случаев process engine предоставляет способ получать и изменять сериализованное значение. В итоге это сводится к двум API:
-
Java Object Value API: переменные представлены как Java‑объекты. Эти объекты можно напрямую устанавливать как значения и извлекать в том же виде. Это более простой API и рекомендуемый способ при реализации кода как части process application.
-
Typed Value API: значения переменных оборачиваются в так называемые типизированные значения (typed values), которые используются для установки и получения переменных. Типизированное значение предоставляет доступ к метаданным, таким как способ сериализации переменной движком и, в зависимости от типа, сериализованное представление переменной. Метаданные также содержат информацию о том, является ли переменная transient или нет.
В качестве примера следующий код получает и устанавливает две целочисленные переменные, используя оба API:
// Java Object API: Get Variable
Integer val1 = (Integer) execution.getVariable("val1");
// Typed Value API: Get Variable
IntegerValue typedVal2 = execution.getVariableTyped("val2");
Integer val2 = typedVal2.getValue();
Integer diff = val1 - val2;
// Java Object API: Set Variable
execution.setVariable("diff", diff);
// Typed Value API: Set Variable
IntegerValue typedDiff = Variables.integerValue(diff);
execution.setVariable("diff", typedDiff);
Специфика этого кода подробнее описана в разделах про Java Object Value API link:{{< relref "#java-object-api" >}}[] и Typed Value API link:{{< relref "#typed-value-api" >}}[].
Установка переменных в конкретную область видимости (Setting variables to specific scope)
Существует возможность устанавливать переменные в конкретную область видимости из скриптов, input\output mapping, listener’ов и service task’ов. Реализация этой функциональности использует id активности (activity id), чтобы идентифицировать целевую область видимости, и выбросит исключение, если не найдена область видимости, в которую нужно установить переменную. Кроме того, как только целевая область найдена, переменная будет установлена в ней локально, что означает: распространение (propagation) в родительскую область не будет выполнено, даже если в целевой области нет переменной с заданным id.
Ниже приведён пример использования в script executionListener:
<camunda:executionListener event="end">
<camunda:script scriptFormat="groovy"><![CDATA[execution.setVariable("aVariable", "aValue","aSubProcess");]]></camunda:script>
</camunda:executionListener>
Другой пример использования — input\output mapping с реализацией DelegateVariableMapping
public class SetVariableToScopeMappingDelegate implements DelegateVariableMapping {
@Override
public void mapInputVariables(DelegateExecution superExecution, VariableMap subVariables) {
}
@Override
public void mapOutputVariables(DelegateExecution superExecution, VariableScope subInstance) {
superExecution.setVariable("aVariable","aValue","aSubProcess");
}
}
здесь переменная будет установлена локально в "aSubProcess" и не будет распространена в родительскую область, даже если ранее переменная локально в "aSubProcess" не была установлена.
Поддерживаемые значения переменных (Supported Variable Values)
Process engine поддерживает следующие типы значений переменных:

В зависимости от фактического значения переменной ей присваивается разный тип. Из доступных типов девять являются примитивными (primitive) типами значений, то есть хранят значения простых стандартных классов JDK без дополнительной метаинформации:
-
boolean: экземплярыjava.lang.Boolean -
bytes: экземплярыbyte[] -
short: экземплярыjava.lang.Short -
integer: экземплярыjava.lang.Integer -
long: экземплярыjava.lang.Long -
double: экземплярыjava.lang.Double -
date: экземплярыjava.util.Date -
string: экземплярыjava.lang.String -
null: ссылкиnull
Примитивные значения отличаются от других значений переменных тем, что их можно использовать в API‑запросах (например, запросах экземпляров процесса) в качестве условий фильтрации.
Тип file можно использовать для хранения содержимого файла или input stream вместе с метаданными, такими как имя файла, кодировка и MIME‑тип, которому соответствует содержимое файла.
Тип значения object представляет пользовательские Java‑объекты. При сохранении такой переменной её значение сериализуется в соответствии с процедурой сериализации. Эти процедуры настраиваемые и взаимозаменяемые.
|
Значения |
Переменные процесса могут храниться в форматах JSON и XML, предоставляемых плагином OpenBPM Engine Spin. Spin предоставляет сериализаторы для переменных типа object, так что Java‑переменные могут сохраняться в базу данных в этих форматах. Кроме того, возможно хранить JSON- и XML-документы напрямую как Spin‑объект с помощью типов значений xml и json. В отличие от обычных переменных string, Spin‑объекты предоставляют fluent API для выполнения типовых операций над такими документами, например, чтения и записи свойств.
Сериализация object-значений (Object Value Serialization)
Когда значение object передаётся в process engine, можно указать формат сериализации (serialization format), чтобы сказать движку сохранить значение в конкретном формате. На основании этого формата движок находит serializer. Serializer умеет сериализовать Java‑объект в указанный формат и десериализовать его из представления в этом формате. Это означает, что могут существовать разные serializer’ы для разных форматов, и возможно реализовать пользовательские serializer’ы, чтобы сохранять пользовательские объекты в определённом формате.
Process engine поставляется с одним встроенным serializer’ом объектов для формата application/x-java-serialized-object. Он может сериализовать Java‑объекты, которые реализуют интерфейс java.io.Serializable, и применяет стандартную Java‑сериализацию объектов.
Желаемый формат сериализации можно указать при установке переменной с использованием Typed Value API:
CustomerData customerData = new CustomerData();
ObjectValue customerDataValue = Variables.objectValue(customerData)
.serializationDataFormat(Variables.SerializationDataFormats.JAVA)
.create();
execution.setVariable("someVariable", customerDataValue);
Кроме того, в конфигурации process engine есть опция defaultSerializationFormat, которая используется, когда никакой конкретный формат не запрошен. По умолчанию она равна application/x-java-serialized-object.
Обратите внимание, что встроенный serializer преобразует объекты в байтовые потоки (byte streams), которые можно интерпретировать только при наличии соответствующего Java‑класса. При реализации task forms, основанных на сложных объектах, следует использовать текстовый формат сериализации, поскольку Tasklist не может интерпретировать такие байтовые потоки. См. блок *Serializing Objects to XML and JSON* для подробностей о том, как интегрировать форматы сериализации вроде XML и JSON. |
xref:openbpm:engine:user-guide/data-formats/index.adoc[Плагин OpenBPM Engine Spin] предоставляет сериализаторы, способные сериализовать object-значения в XML и JSON. Их можно использовать, когда требуется, чтобы сериализованные значения объектов могли быть понятны человеку, или когда сериализованное значение должно быть осмысленным без наличия соответствующего Java‑класса. При использовании предварительно собранного (pre-built) дистрибутива OpenBPM Engine, OpenBPM Engine Spin уже предварительно настроен, и вы можете попробовать эти форматы без дополнительной конфигурации. |
Java Object API
Самый удобный способ работы с переменными процесса из Java — использовать их Java‑объектное представление. Везде, где process engine предоставляет доступ к переменным, переменные процесса можно получать в этом представлении при условии, что для пользовательских объектов движку известны задействованные классы. Например, следующий код устанавливает и получает переменную для заданного экземпляра процесса:
com.example.Order order = new com.example.Order();
runtimeService.setVariable(execution.getId(), "order", order);
com.example.Order retrievedOrder = (com.example.Order) runtimeService.getVariable(execution.getId(), "order");
Обратите внимание, что этот код устанавливает переменную на максимально возможном верхнем уровне в иерархии областей видимости переменных. Это означает: если переменная уже присутствует (либо в этом execution, либо в любой из его родительских областей), она обновляется. Если переменной ещё нет, она создаётся в самой верхней области, то есть в экземпляре процесса. Если переменную нужно установить строго на переданном execution, можно использовать локальные (local) методы. Например:
com.example.Order order = new com.example.Order();
runtimeService.setVariableLocal(execution.getId(), "order", order);
com.example.Order retrievedOrder = (com.example.Order) runtimeService.getVariable(execution.getId(), "order");
com.example.Order retrievedOrder = (com.example.Order) runtimeService.getVariableLocal(execution.getId(), "order");
// both methods return the variable
Каждый раз, когда переменная устанавливается в её Java‑представлении, process engine автоматически определяет подходящий serializer значения или выбрасывает исключение, если переданное значение невозможно сериализовать.
Typed Value API
В случаях, когда важно получить доступ к сериализованному представлению переменной или когда движку нужно явно указать сериализовать значение в определённом формате, можно использовать API на основе typed values. По сравнению с API на основе Java‑объектов, этот API оборачивает значение переменной в так называемое типизированное значение (Typed Value). Такое типизированное значение обеспечивает более богатое представление значений переменных.
Для удобного построения typed values OpenBPM Engine предоставляет класс io.openbpm.bpm.engine.variable.Variables. Этот класс содержит статические методы, которые позволяют создавать отдельные typed values, а также создавать map typed values во fluent‑стиле.
Примитивные значения (Primitive Values)
Следующий код устанавливает одну переменную String, задавая её как typed value:
StringValue typedStringValue = Variables.stringValue("a string value");
runtimeService.setVariable(execution.getId(), "stringVariable", typedStringValue);
StringValue retrievedTypedStringValue = runtimeService.getVariableTyped(execution.getId(), "stringVariable");
String stringValue = retrievedTypedStringValue.getValue(); // equals "a string value"
Обратите внимание, что в этом API появляется ещё один уровень абстракции вокруг значения переменной. Поэтому, чтобы получить истинное значение, необходимо распаковать (unwrap) фактическое значение.
Значения файлов (File Values)
Разумеется, для простых значений String API на основе Java‑объектов более лаконичен. Поэтому рассмотрим значения более богатых структур данных.
Файлы могут сохраняться в базе данных как BLOB. Тип значения file позволяет вместе с ним хранить дополнительную метаинформацию, такую как имя файла и MIME‑тип. Следующий пример кода создаёт file value из текстового файла:
FileValue typedFileValue = Variables
.fileValue("addresses.txt")
.file(new File("path/to/the/file.txt"))
.mimeType("text/plain")
.encoding("UTF-8")
.create();
runtimeService.setVariable(execution.getId(), "fileVariable", typedFileValue);
FileValue retrievedTypedFileValue = runtimeService.getVariableTyped(execution.getId(), "fileVariable");
InputStream fileContent = retrievedTypedFileValue.getValue(); // a byte stream of the file contents
String fileName = retrievedTypedFileValue.getFilename(); // equals "addresses.txt"
String mimeType = retrievedTypedFileValue.getMimeType(); // equals "text/plain"
String encoding = retrievedTypedFileValue.getEncoding(); // equals "UTF-8"
Изменение file value (Changing a File Value)
Чтобы изменить или обновить значение file, необходимо создать новый FileValue с тем же именем и новым содержимым, поскольку все typed values являются неизменяемыми (immutable):
InputStream newContent = new FileInputStream("path/to/the/new/file.txt");
FileValue fileVariable = execution.getVariableTyped("addresses.txt");
Variables.fileValue(fileVariable.getName()).file(newContent).encoding(fileVariable.getEncoding()).mimeType(fileVariable.getMimeType()).create();
Object-значения (Object Values)
Пользовательские Java‑объекты могут сериализоваться с типом значения object. Пример с использованием typed value API:
com.example.Order order = new com.example.Order();
ObjectValue typedObjectValue = Variables.objectValue(order).create();
runtimeService.setVariableLocal(execution.getId(), "order", typedObjectValue);
ObjectValue retrievedTypedObjectValue = runtimeService.getVariableTyped(execution.getId(), "order");
com.example.Order retrievedOrder = (com.example.Order) retrievedTypedObjectValue.getValue();
Это снова эквивалентно API на основе Java‑объектов. Однако теперь можно указать движку, какой формат сериализации использовать при сохранении значения. Например:
ObjectValue typedObjectValue = Variables
.objectValue(order)
.serializationDataFormat(Variables.SerializationDataFormats.JAVA)
.create();
создаёт значение, которое сериализуется встроенным Java object serializer’ом движка. Также полученный экземпляр ObjectValue предоставляет дополнительные сведения о переменной:
// returns true
boolean isDeserialized = retrievedTypedObjectValue.isDeserialized();
// returns the format used by the engine to serialize the value into the database
String serializationDataFormat = retrievedTypedObjectValue.getSerializationDateFormat();
// returns the serialized representation of the variable; the actual value depends on the serialization format used
String serializedValue = retrievedTypedObjectValue.getValueSerialized();
// returns the class com.example.Order
Class<com.example.Order> valueClass = retrievedTypedObjectValue.getObjectType();
// returns the String "com.example.Order"
String valueClassName = retrievedTypedObjectValue.getObjectTypeName();
Детали сериализации полезны, когда вызывающее приложение не располагает классами фактического значения переменной (то есть com.example.Order не известен). В таких случаях вызов runtimeService.getVariableTyped(execution.getId(), "order") выбросит исключение, поскольку он сразу пытается десериализовать значение переменной. В таком случае можно использовать вызов runtimeService.getVariableTyped(execution.getId(), "order", false). Дополнительный boolean‑параметр говорит process engine не пытаться выполнять десериализацию. В этом случае вызов isDeserialized() вернёт false, а вызовы вроде getValue() и getObjectType() будут выбрасывать исключения. Вызов getValueSerialized() и getObjectTypeName() позволяет получить доступ к переменной несмотря на это.
Аналогично, возможно установить переменную, используя её сериализованное представление:
String serializedOrder = "...";
ObjectValue serializedValue =
Variables
.serializedObjectValue(serializedOrder)
.serializationDataFormat(Variables.SerializationDataFormats.JAVA)
.objectTypeName("com.example.Order")
.create();
runtimeService.setVariableLocal(execution.getId(), "order", serializedValue);
ObjectValue retrievedTypedObjectValue = runtimeService.getVariableTyped(execution.getId(), "order");
com.example.Order retrievedOrder = (com.example.Order) retrievedTypedObjectValue.getValue();
НЕСОГЛАСОВАННЫЕ СОСТОЯНИЯ ПЕРЕМЕННЫХ (INCONSISTENT VARIABLE STATES):
При установке сериализованного значения переменной не выполняется проверка того, совместима ли структура сериализованного значения с классом, экземпляром которого должно быть значение переменной. При установке переменной из примера выше переданное сериализованное значение не валидируется по структуре com.example.Order. Таким образом, некорректное значение переменной будет обнаружено только при вызове runtimeService#getVariableTyped.
Имейте в виду, что при использовании сериализованного представления переменных формат Java serialization по умолчанию запрещён. Вам следует либо использовать другой формат (JSON или XML), либо явно включить Java serialization с помощью конфигурационного флага xref:openbpm:engine:reference/deployment-descriptors/tags/process-engine.adoc#javaSerializationFormatEnabled[`javaSerializationFormatEnabled`]. Однако перед включением обязательно ознакомьтесь с разделом xref:openbpm:engine:user-guide/security.adoc#variable-values-from-untrusted-sources[Security Implication]. |
Значения JSON и XML (JSON and XML Values)
Плагин OpenBPM Engine Spin предоставляет абстракцию для JSON- и XML-документов, упрощающую их обработку и модификацию. Это часто удобнее, чем хранить такие документы как обычные переменные string. Подробности см. в документации OpenBPM Engine SPIN о хранении JSON-документов и хранении XML-документов.
Transient-переменные (Transient variables)
Объявление transient-переменных возможно только через API на основе typed values. Они не сохраняются в базе данных и существуют только в рамках текущей транзакции. Любое состояние ожидания (waiting state) во время выполнения экземпляра процесса приводит к потере всех transient‑переменных. Обычно это происходит, например, когда внешний сервис временно недоступен, достигнута user task или выполнение процесса ожидает сообщение, сигнал или условие. Используйте эту возможность осторожно.
Переменные любого типа link:{{<relref "#supported-variable-values">}}[] можно объявить transient, используя класс Variables и установив параметр isTransient в true.
// primitive values
TypedValue typedTransientStringValue = Variables.stringValue("foobar", true);
// object value
com.example.Order order = new com.example.Order();
TypedValue typedTransientObjectValue = Variables.objectValue(order, true).create();
// file value
TypedValue typedTransientFileValue = Variables.fileValue("file.txt", true)
.file(new File("path/to/the/file.txt"))
.mimeType("text/plain")
.encoding("UTF-8")
.create();
Transient‑переменные можно использовать через REST API, например, {{< restref page="startProcessInstance" text="when starting a new process instance" tag="Process-Definition" >}}.
Установка нескольких typed values (Set Multiple Typed Values)
Подобно API на основе Java‑объектов, также возможно установить несколько typed values одним вызовом API. Класс Variables предоставляет fluent API для построения map typed values:
com.example.Order order = new com.example.Order();
VariableMap variables =
Variables.createVariables()
.putValueTyped("order", Variables.objectValue(order).create())
.putValueTyped("string", Variables.stringValue("a string value"))
.putValueTyped("stringTransient", Variables.stringValue("foobar", true));
runtimeService.setVariablesLocal(execution.getId(), "order", variables);
Взаимозаменяемость API (Interchangeability of APIs)
Оба API предоставляют разные представления одних и тех же сущностей и поэтому могут комбинироваться так, как вам нужно. Например, переменная, установленная через API на основе Java‑объектов, может быть получена как typed value, и наоборот. Поскольку класс VariableMap реализует интерфейс Map, в этот map также можно помещать как обычные Java‑объекты, так и typed values.
Какой API следует использовать? Тот, который лучше соответствует вашей цели. Если вы уверены, что всегда имеете доступ к задействованным классам значений, например, при реализации кода в process application вроде JavaDelegate, то API на основе Java‑объектов проще в использовании. Когда вам нужен доступ к метаданным, специфичным для значения, таким как форматы сериализации, или требуется объявить переменную transient, следует использовать API на основе typed values.
Input/Output Variable Mapping
Чтобы повысить переиспользуемость исходного кода и бизнес-логики, OpenBPM Engine предлагает input/output mapping переменных процесса. Это можно использовать для задач (tasks), событий (events) и подпроцессов (subprocesses).
Чтобы использовать mapping переменных, к элементу необходимо добавить OpenBPM Engine extension element
inputOutput.
Он может содержать несколько элементов
inputParameter
и outputParameter,
которые определяют, какие переменные должны быть сопоставлены (mapped). Атрибут name элемента
inputParameter
обозначает имя переменной внутри активности (локальная переменная, которая будет создана), тогда как атрибут name элемента
outputParameter
обозначает имя переменной вне активности.
Содержимое input/outputParameter задаёт значение, которое сопоставляется соответствующей переменной.
Это может быть простая константная строка или выражение. Пустое тело устанавливает переменную
в значение null.
<camunda:inputOutput>
<camunda:inputParameter name="x">foo</camunda:inputParameter>
<camunda:inputParameter name="willBeNull"/>
<camunda:outputParameter name="y">${x}</camunda:outputParameter>
<camunda:outputParameter name="z">${willBeNull == null}</camunda:outputParameter>
</camunda:inputOutput>
Можно использовать даже сложные структуры, такие как lists и maps. Обе структуры также могут быть вложенными.
<camunda:inputOutput>
<camunda:inputParameter name="x">
<camunda:list>
<camunda:value>a</camunda:value>
<camunda:value>${1 + 1}</camunda:value>
<camunda:list>
<camunda:value>1</camunda:value>
<camunda:value>2</camunda:value>
<camunda:value>3</camunda:value>
</camunda:list>
</camunda:list>
</camunda:inputParameter>
<camunda:outputParameter name="y">
<camunda:map>
<camunda:entry key="foo">bar</camunda:entry>
<camunda:entry key="map">
<camunda:map>
<camunda:entry key="hello">world</camunda:entry>
<camunda:entry key="camunda">bpm</camunda:entry>
</camunda:map>
</camunda:entry>
</camunda:map>
</camunda:outputParameter>
</camunda:inputOutput>
Также можно использовать скрипт для задания значения переменной. См. соответствующий раздел Use scripts as input/output parameters в главе про scripting, чтобы узнать, как указать скрипт.
Простой пример пользы input/output mapping — сложное вычисление, которое должно быть частью нескольких определений процессов. Такое вычисление может быть разработано как изолированный delegation code или как скрипт и переиспользовано в каждом процессе, даже если процессы используют разные наборы переменных. Input mapping используется, чтобы сопоставить различные переменные процесса с требуемыми input‑параметрами активности сложного вычисления. Соответственно, output mapping позволяет использовать результат вычисления в дальнейшем выполнении процесса.
Подробно: предположим, что такое вычисление реализовано Java Delegate классом io.openbpm.bpm.example.ComplexCalculation.
Этому delegate в качестве входных
параметров требуются переменные userId и costSum.
Затем он вычисляет три значения: pessimisticForecast, realisticForecast и optimisticForecast,
которые являются разными прогнозами будущих затрат клиента. В первом процессе обе входные переменные доступны как переменные процесса, но под другими именами (id, sum). Из трёх результатов процесс использует только realisticForecast, на который он ссылается по имени forecast в последующих активностях. Соответствующий input/output mapping выглядит так:
<serviceTask camunda:class="io.openbpm.bpm.example.ComplexCalculation">
<extensionElements>
<camunda:inputOutput>
<camunda:inputParameter name="userId">$\{id}</camunda:inputParameter>
<camunda:inputParameter name="costSum">$\{sum}</camunda:inputParameter>
<camunda:outputParameter name="forecast">$\{realisticForecast}</camunda:outputParameter>
</camunda:inputOutput>
</extensionElements>
</serviceTask>
Во втором процессе предположим, что переменная costSum должна вычисляться из свойств трёх разных map. Также процесс
зависит от переменной avgForecast как среднего значения трёх прогнозов. В этом случае mapping выглядит так:
<serviceTask camunda:class="io.openbpm.bpm.example.ComplexCalculation">
<extensionElements>
<camunda:inputOutput>
<camunda:inputParameter name="userId">${id}</camunda:inputParameter>
<camunda:inputParameter name="costSum">
${mapA[costs] + mapB[costs] + mapC[costs]}
</camunda:inputParameter>
<camunda:outputParameter name="avgForecast">
${(pessimisticForecast + realisticForecast + optimisticForecast) / 3}
</camunda:outputParameter>
</camunda:inputOutput>
</extensionElements>
</serviceTask>
IO Mapping для multi-instance (Multi-instance IO Mapping)
Input mapping также можно использовать с multi-instance конструкциями, в которых mapping применяется для каждого создаваемого экземпляра. Например, для multi-instance подпроцесса с пятью экземплярами mapping выполняется пять раз, и задействованные переменные создаются в каждой из пяти областей подпроцесса так, что к ним можно обращаться независимо.
|
Движок не поддерживает output mapping для multi-instance конструкций. Каждый экземпляр output mapping перезаписывал бы переменные, установленные предыдущими экземплярами, и итоговое состояние переменных стало бы трудно предсказать. |
IO mapping на отменённых активностях (IO Mapping on canceled activities)
Если активность отменена (например, из‑за выбрасывания BPMN error), IO mapping всё равно выполняется. Это может приводить к исключениям, если output mapping ссылается на переменные, которые в тот момент не существуют в области активности.
Поведение по умолчанию: движок всё равно пытается выполнить output mapping на отменённых активностях и завершает с исключением, если переменная не найдена. При включении конфигурационного флага движка skipOutputMappingOnCanceledActivities (то есть установке его в true) движок не будет выполнять output mapping ни на одной отменённой активности.
Лицензия и атрибуция
Эта документация была создана на базе материала "Camunda 7 Docs" от Camunda, находится под лицензией Creative Commons Attribution-ShareAlike 3.0 Unported License .
Оригинал документации: https://docs.camunda.org