Administrationshandbuch d.velop process

Administration manual d.velop process

Basic information on the application and the manual

In this chapter, you will find product hints and general information.

About d.velop process

d.velop process is an application you can use to execute, monitor and administer processes.

d.velop process allows you to automate business processes. You can allow users to participate in the form of tasks or perform automated service activities. d.velop process supports the BPMN standard. This gives you many options when designing processes.

In process monitoring, you have the option to check the status of active processes. If an error occurs, you have the option to apply corrections directly. This is a simple way to ensure the successful execution of your business processes.

The process administration supports you in the performance of actions across several process instances. For example, you can cancel several process instances, migrate them to a new version in case of process changes, retry failed process instances or delete a process version.

If you have modeled your own process, you can deploy it in the process administration. The process will then be available to you in the d.3ecm world.

Configuring d.evelop process

In this topic, you will find information on the configuration and more settings.

Configuring a system user

Configure a system user to allow the application to communicate with other applications requiring authentication.

To configure a system user, proceed as follows:

  1. Select the feature Configuration.
  2. Select the option System user in the Process settings section.
  3. Select the context action Configure.
  4. Enter the API key for the corresponding user. User the context action Open API key creation to determine or generate an API key using d.ecs identity provider.
  5. Click Save.

Setting up user roles (optional)

You can use the entry User roles in the feature Configuration to assign a user role to users. All authenticated users are automatically assigned the role of Process user after the setup of d.velop process. 

You can assign the following roles to users:

  • Process administrator: Has all permissions for working with d.velop process.
  • Process user: Can start single-use processes and deploy processes.

For example, if you want to assign the role of Process administrator to a user, simply enter the user name in the appropriate field and select him/her.

Configuring protocol exports

You would like to configure exports for protocols into a d.3 repository in order to save protocols for long periods.

What you need to know

  • You need a configured d.3 repository in which the protocol exports are saved.
  • You must be logged on with a user that can administer mappings for the d.3 repository.
  • You need to create a document type in your repository that has four properties of the type Alphanumeric (depending on the system also Text) with a maximum length of 250 characters. You need to assign these new properties to the process properties afterwards. Specify meaningful names for the properties which correspond to the process properties, e.g. Process, Process instance, Business key and Attachment.
  • If one of the values is longer than 250 characters (or 255 bytes), this value is truncated as appropriate during the export. Three periods indicate the truncated point.
  • If metadata is truncated or if there is an error during the export process, you will see an appropriate note for the process instance in both process monitoring and in the protocol view.
  • You need to create an API key for a user that has read and write access to this document type.

This is how it works

  1. Open the feature Mappings.
  2. Add a new mapping.
  3. Select the source Processes.
  4. Add a category and link the source Process protocol with the desired document type.
  5. Link all the properties of the source with document properties of the target. Make sure that all four properties have been mapped.
  6. Save the mapping.
  7. Open the feature Configuration and select DMS export configuration in the section Process settings.
  8. Select the target repository and enter the API key.
  9. Save the changes.

After you have configured the protocol export, you can activate the option for exporting the protocol during the definition of a process.


Administration of processes

In this topic, you will find out how to administer your processes. Read about how to get an overview of your processes and how to correct broken processes.

Useful information on the "Process administration" feature

You can use the feature Process administration to start actions affecting entire process versions. Generally, the actions include several process instances. Process administration allows you to perform actions for different processes and versions in sequence without having to change the view.

You can perform the following actions for entire process versions:

  • Retry process versions: If several errors occur in one process, you can retry the process version for troubleshooting. To retry a process version, use the action Retry.
  • Migrate process instances to the next process version: A new version of the process is automatically created when processes are updated. You can use the action Migrate to migrate all instances of a process version to the newest version.
  • Delete process versions: If there are no more running process instances for a version, you can delete the process version. To delete a process version, use the action Delete process version.
  • Cancel process instances: You can cancel all open instances of a process version. By canceling, all open activities for this process version are removed and the process instance cannot be retried. To cancel a process instance, use the action Cancel instances.

The following actions are also available:

  • Deploy new process: You can import a new process (or a new version of an existing process) from a .bpmn file.

Viewing all process instances

The feature Process monitoring can be used to obtain an overview of all process instances. You can use the business key to perform targeted searches of individual processes or limit the list of results using the filters Processes, Versions, Activities and Status. A process has one of the following four statuses:

: The instance was canceled.

: The instance is in an error state.

: The instance was ended successfully.

: The instance is currently still running.

If there is an additional exclamation mark for the status, this indicates an error or a warning during the process’s protocol export.

Select the process to see more detailed information on a process instance. There are context actions available in the detail view which may differ depending on the process type. You can use the context actions to cancel the process instance, migrate it to the next version, view it in an instance diagram or show it in the source. You can also display the process protocol if you want to obtain an overview of the process sequence.

Viewing an instance diagram

In the detail view of an instance, you can view the process instance in a diagram with the context action Instance diagram.

To maintain an overview of very complex instance diagrams, you can change the diagram view. Use the mouse wheel to change the size of the diagram. When you have enlarged the view using the mouse wheel, you can move the diagram by holding the left mouse button. Use Reset view to return to the original view.

Changing the variables of a token

When you navigate to the detail view of a token in the feature Process monitoring, you can change the variables of the process instance. You can change variables to remove the potential error cause of a process, for example.

Select Edit variables to enable the edit mode and change the values in the input fields. There are two options for exiting the edit mode:

  • Select Save changes to write the new values to the database and leave the edit mode. All changes have a direct impact on the entire process.
  • Select Discard changes to restore the initial values and leave the edit mode. This action has no impact on the process. 

Retrying a failed token

When you see a process with the status Error in the feature Process monitoring, you can retry the failed token for troubleshooting. Observe the error cause in the detail view of a token, as you may need to change the variables of the process instance for troubleshooting.

To retry a token, navigate to the detail view of the token. Select Retry and confirm the notice.

Retrying an asynchronous service

When you use an asynchronous service, errors may occur during communication with the external service when you execute the service activity. The error can occur if the service endpoint accepts the service request but does not respond to it owing to technical problems. You can call the service again in process monitoring to rectify this error.

This is how it works

  1. Open the process instance concerned and the service token for which there was no response in the feature Process monitoring.
  2. Select Move token.
  3. Select the target activity for the token and confirm the dialog.

Useful information on protocolling processes

If you want to be able to trace the runs of individual process instances, you can activate protocolling for the associated process version.

There are two options for displaying the protocol: In process monitoring, you can use the context action Process protocol to display the protocol. For tasks that are part of a protocolled process, you can display the protocolling in the perspective Process in the task overview.

Different views

There are two different views for the process protocols:

  • The professional view focuses on user activities. In the professional view, the protocol contains information about the process start and the process end, user activities, persons involved, and data entered.
  • All the activities of the process instance that have been run through are processed in the technical view. That includes all the items that exist in the BPMN definition, service calls, error situations that have occurred, and many other technical details. Technical views of protocols are available only in process monitoring.

Protocol storage

Protocols are available during the entire runtime of a process instance. The protocols can be stored for up to one year after the process instance is completed, depending on the configuration. The protocol data is deleted after the storage period has expired.

Exporting protocols to a d.3 repository

If you would like to store protocol data beyond the storage period, you can save the protocols in your d.3 repository. To save protocols in the repository, the first thing you need to do is configure the protocol export. After a process instance has been completed, the protocol is then automatically saved in your d.3 repository.

You can still display the protocols in process monitoring and in the task view after the export.

Special process variables

For user tasks, you can add additional information to the protocol in the form of a decision and a comment. To do this, you can use an editing dialog to transfer the process variables dv_decision and dv_comment.

The content is highlighted in a special manner in the protocol.

Activating protocolling for a process definition

When you deploy a process definition, you can activate protocolling. By default, protocols are stored for 30 days starting at the end of the process.

You must configure protocolling separately for each process.

This is how it works

  1. Open the feature Process administration.
  2. Select the action Deploy new process.
  3. Select the BPMN file you want to deploy.
  4. Click Upload.
  5. Click Protocol to open the settings for the protocolling.
  6. Activate the protocolling.
  7. You also have the option of activating protocol exports to your d.3 repository, which allows you to use audit-compliant archiving.
  8. Change the storage time of the protocols if necessary.
  9. Confirm the dialog with Deploy.

If you deploy a new version of a process definition, the most recently used settings for protocolling the process version are applied. If you would like to change the settings later on, you need to deploy the process definition again.


Modeling of processes

In this topic, you will find out how to model your own processes. You will get to know the supported BPMN items and find out how to add these to your processes.

Useful information on process modeling

For the creation of process models, the application supports the BPMN standard. This is an XML-based format. The modeling of processes in the d.velop context is aligned with the standard of the Object Management Group (OMG). The value http://www.omg.org/spec/BPMN/20100524/MODEL is the default namespace.

For the modeling of process models, we recommend using the camunda modeler (https://camunda.com/). All examples of this documentation were created like this.

Using BPMN items

When creating your own process models, you can use the following BPMN items of BPMN standard 2.0:

BPMN itemRestrictions

Start event

Permitted event types: None

Only in event-based subprocesses: Escalation, error

End event

Permitted event types: None, termination, escalation, error

 


Intermediate boundary event

Permitted event types: Timer, escalation, error

Intermediate catch event (attached intermediate event with a waiting function)

Permitted event types: timer

Intermediate throw event (attached intermediate event with a triggering function)Permitted event types: Escalation

User Task (User activity)


 

Send Task (Send activity)Only for connecting services.

 

Receive Task (Receive activity)


Only for connecting services.

Gateway

Permitted gateway types: Exclusive, parallel, inclusive.

Sequence flow


Subprocess

Permitted subprocess types: Normal, event-based (see start event)

General restrictions

The following restrictions apply to all items:

  • Expressions of input and output parameters are subject to the restrictions on expressions.
  • Only the following camunda extensions are permitted:
    • camunda:inputOutput
    • camunda:properties
    • camunda:property
    • camunda:failedJobRetryTimeCycle
    • camunda:asyncBefore
    • camunda:asyncAfter
    • camunda:formKey


Creating a sample process in a BPMN file

When getting started with the modeling of your own processes, it is useful to create a simple process as an example first. Prerequisite for the modeling of your own processes are a set user roles. In addition, you need a text or BPMN editor with XML view and a tool to call a REST API.

A simple process will look like this:

To model your own process, first create the following basic structure in your BPMN file:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" targetNamespace="">
  <process>
    <startEvent />
    <sequenceFlow />
    <userTask />
    <sequenceFlow />
    <endEvent />
  </process>
</definitions>

To this basic structure, add the individual process items.

Adding the process item

The BPMN item process encapsulates the entire process. Add the properties id, name and isExcecutable to the BPMN item.

<process id="hello_world_process" name="Hello World Process" isExecutable="true">

Explanation of the properties

  • id: This property is used as a unique identifier for the process.
  • name: This property is used as a display name in the user interfaces.
  • isExecutable: This property must contain the value true to enable the process to be started.

Adding a start and end event

The BPMN items startEvent and endEvent are used as markings which indicate where the process begins and where it ends. Add the property id to the respective BPMN items.

<startEvent id="start" />
<endEvent id="end" />

Adding a user activity

The BPMN item userTask stands for a user activity in the process. When this activity is entered, one or more users are assigned a task. Add the properties id, name and camunda:assignee to the BPMN item.

<userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />    

Explanation of the properties

  • id: This property serves as an identifier of the activity in the BPMN model and is used for the connection by means of sequence flows.
  • name: This property is added as a subject to the task.
  • camunda:assignee: This property refers to the person who is to process the task. In the BPMN file, the expression ${variables.get("dv_initiator")} uses a variable. The variable dv_initiator always refers to the person who has started the process. The task is therefore always assigned to the person starting the process.

Adding sequence flows

Connect the individual process items to create a sequence. To connect the process items, use the BPMN item sequenceFlow. Add the properties idsourceRef and targetRef to the BPMN item.

The sample configuration in the BPMN file shows how you connect the start event to the user activity and link the user activity with the end event:

<sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
<sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />

Explanation of the properties

  • id: This property is a unique identifier for the sequence flow within the BPMN model.
  • sourceRef: This property refers to the starting point of the sequence flow.
  • targetRef: This property refers to the target of the sequence flow. In this property you enter the identifiers of the items to be connected.

After you have added the individual process items, the BPMN file will look as follows:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" targetNamespace="">
  <process id="hello_world_process" name="Hello World Process" isExecutable="true">
    <startEvent id="start" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />     
	<userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />        
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
    <endEvent id="end" />
  </process>
</definitions>

Adding graphic information

If you want to view your created process in a diagram, you can add graphic information to the BPMN file. This graphic information defines the size of the diagram and the position of the individual items. You add the graphic information by means of the BPMN item bmpndi:BPMNDiagram.

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" targetNamespace="">
  <process id="hello_world_process" name="Hello World Process" isExecutable="true">
    <startEvent id="start" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
    <userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />    
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
    <endEvent id="end" />
  </process>
   
  <!-- Diagram information -->
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane" bpmnElement="hello_world_process">
      <bpmndi:BPMNShape id="start_di" bpmnElement="start">
        <dc:Bounds x="173" y="102" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="s1_di" bpmnElement="s1">
        <di:waypoint x="209" y="120" />
        <di:waypoint x="259" y="120" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="task_hello_world_di" bpmnElement="task_hello_world">
        <dc:Bounds x="259" y="80" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="s2_di" bpmnElement="s2">
        <di:waypoint x="359" y="120" />
        <di:waypoint x="409" y="120" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="end_di" bpmnElement="end">
        <dc:Bounds x="409" y="102" width="36" height="36" />
      </bpmndi:BPMNShape>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Using expressions

You can use variable expressions for the modeling of processes. The expressions use the syntax of the Java Expression Language.

Expressions may only use the following items:

ItemRestriction

Read access to the variables using variables.

  • variables.get
  • variables.getObject
  • variables.getDisplayValue

Generating multi-values

  • collections.from

Read access to values of the current process instance

  • process.instance.id
    • ID of the current process instance
  • process.instance.businessKey
    • Business key of the current process instance

Operators and characters

Permitted operators and characters: +, -, *, /, %, =, !, <, >, &, |, ?, (, ), [, ].

KeywordPermitted keywords: div, mod, eq, ne, lt, gt, le, ge, and, or, not, empty.
Numeric values
StringsStrings must be put between " " or ' '.

Examples

${"Hello World"}                            // Hello World
${3}                                        // 3
${3 > 4}                                    // false
${variables.get("myVariable")}              // Value of myVariable
${variables.get("myVariable") == "Hello"}   // true, if myVariable equals Hello, false otherwise
${collections.from("a", "b", "c")}          // creates a collection with "a", "b" and "c"

Hybrid forms are also possible, making it possible to directly combine texts and variable content.

Examples

This is an expression with ${variables.get("myVariable")}
3 is ${(3 > 4) ? "greater" : "lesser"} than 4

Working with process variables

In this topic, you will find out how to dynamically create your processes using variables.

Useful information on process variables

Process variables are data containing information on a process instance. The following process variables are included in every process instance:

  • dv_initiator: A process variable of data type Identity. The process variable refers to the identity of the user who has started the process instance.
  • dv_start_time: A process variable of data type String. The process variable includes the UTC string of the time at which the process instance was started from the point of view of the application. The time at which the application was instructed to start the process instance applies. As the actual (technical) start of the instance is performed asynchronously, the time included in the variable may vary.

Using other process variables

You can use these variables for special purposes:

  • dv_sender: A process variable of data type Identity. The process variable refers to the identity of the user who is used as the sender of user activities.
  • dv_attachment: A process variable of data type DmsObject or other. The process variable includes a link which is added as an attachment to all user activities.
  • dv_decision: A process variable of the type String. For tasks, this text is highlighted as a decision in the process protocol.
  • dv_comment: A process variable of the type String. For tasks, this text is highlighted as a comment in the process protocol.

Important

The process variable dv_attachment is predefined with the data type DmsObject . If you want to use a different URI than that for an object of the DMS app, you need to change the value of the data type to String.

Defining process variables

In the process definition, you can define variables that are used within a process. Defined variables can be automatically validated and, if necessary, converted at the appropriate interfaces of the application. 

You can define the following variables within a process:

  • General process variable: A variable which is valid in the entire process. You can specify whether it is a start variable.
  • Local process variable: A variable with a scope that is limited to a single process activity. 
  • Service variables: Input or output variables of a process service. 

A variable definition contains the following information:

PropertyPossible valuesExample
Name[A-Za-z][A-Za-z0-9_]*myVariable (name property)
Start variablemyStartVariable* (name property)
Data type
  • String
  • Number
  • Identity
  • DmsObject
  • URL
String (value property)
Single or multi-value

Single value: String (value property)

Multi-value: [String] (value property)

Mandatory variable

Single value: String! (value property)

Multi-value: [String]! (value property)

Please consider the following important notes when using process variables:

  • Name prefix "dv_": You must not use the name prefix dv_ for variables. These variables are reserved for internal variables. You may use the name prefix dv_ only when overwriting the variable definition dv_attachment .
  • Changing variable definitions when switching the version: If you change the data type of a variable or switch between a single value and a multi-value between different versions of a process, errors may occur in the execution of the process after the migration. These errors occur if existing process instances already contain values for the corresponding variables in the previous definition. After migrating to the new version, these values lose their validation. Always make sure that no process instance requiring migration is affected when changing the variable definition.

Note

You cannot delete a variable which is defined as a mandatory variable via the interface for changes to variables. If the mandatory variable is also a start variable, a user always needs to transfer a valid value when a process instance is started. If he does not transfer a valid value, the request will be rejected with the error code 400.

For data type Number the following restrictions apply:

MinimumMaximumDecimal placesAccuracy
-1e16

1e16

515 places

The non-primitive data types use the following notation:

Data typeNotation
Identity

For users:
identity:///identityprovider/scim/users/<someUserId>

For groups:
identity:///identityprovider/scim/groups/<someGroupId>

DmsObjectdmsObject:///dms/r/<repositoryId>/o2/<dmsObjectId>
URLhttps://www.d-velop.de (max. 2,000 characters)

Variables are defined as a BPMN extension in the form of Camunda properties. In the BPMN model, you define general process and service variables directly in the process node. You define local process variables in the node of the activity in which they are to apply.

General process and service variables

 <process id="myProcess" name="Process with variable declaration" isExecutable="true">
    <extensionElements>
        <camunda:properties>
            <camunda:property name="variable:myVariable" value="[String]!" /> <!-- Name: "myVariable", Type: "String", Multiple: true, Mandatory: true, Startvariable: false -->
            <camunda:property name="variable:myStartVariable*" value="String" /> <!-- Name: "myStartVariable", Type: "String", Multiple: false, Mandatory: false, Startvariable: true-->
            <camunda:property name="variable:someUserTaskOutput" value="String" /> <!-- Name: "someUserTaskOutput", Type: "String", Multiple: false, Mandatory: false, Startvariable: false -->
            <camunda:property name="service:/myservice:in:input" value="String!" /> <!-- Name: "input", Type: "String", Multiple: false, Mandatory: true -->
            <camunda:property name="service:/myservice:out:output" value="Number!" /> <!-- Name: "output", Type: "Number", Multiple: false, Mandatory: true -->
        </camunda:properties>
    </extensionElements>
</userTask>

Local process variable

<userTask id="userTask" name="User Task">
    <extensionElements>
        <camunda:inputOutput>
            <camunda:inputParameter name="someInput">user task input which is only available within this user task scope</camunda:inputParameter>
            <camunda:outputParameter name="someUserTaskOutput">user task output which will be written to process scope</camunda:outputParameter>
        </camunda:inputOutput>
        <camunda:properties>
            <camunda:property name="variable:someInput" value="String" />
        </camunda:properties>
    </extensionElements>
</userTask>

Using process variables

When modeling your own processes, you can use process variables to create dynamic processes. When getting started with process variables, it is useful to create a simple process with one user activity first. This process will e.g. look like this:


The BPMN of this sample process is structures as follows. To simplify the example, the graphic information on the BPMN diagram is not included in this BPMN sample file.

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" targetNamespace="">
  <process id="GettingStarted" name="Beispiel: Einstieg" isExecutable="true">
    <startEvent id="start"/>
    <userTask id='task_hello_world' name='Hello World' camunda:assignee="${variables.get('dv_initiator')}" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
	<sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
    <endEvent id="end"/>        
  </process>  
</definitions>

Now add a new variable definition to this process definition.

Adding a variable definition

To be able to use a process variable, you need to add it to the process definition. In the process definition, you add the BPMN items extensionElements and camunda:properties to the BPMN item process. To define the process variable, then add the item camunda:property to the BPMN item camunda:properties.

This example shows how to add the variable message of data type String:

<process id="GettingStarted" name="Beispiel: Einstieg" isExecutable="true">
	<extensionElements>
      <camunda:properties>
        <camunda:property name="variable:message" value="String" />
      </camunda:properties>
    </extensionElements>
	...
</process>

Explanation of the properties

  • name: This property defines the name of the process variable. The value is always preceded by the prefix variable:.
  • value: This property defines the data type of the process variable.

Using the process variable

You can now use the variable message for the name of the user activity, so that this name is displayed to the user in the task list. To do so, replace the existing test in the property name of the user activity with the method for access to the variable message:

<process id="GettingStarted" name="Beispiel: Einstieg" isExecutable="true">
	...
	<userTask id="task_hello_world" name="${variables.get('message')}" camunda:assignee="${variables.get('dv_initiator')}" />
	...

You can now define the value of the variable e.g. for the start of the process.


Determining process variables

Using the object variables you can access the process variables. In each case, the call is executed using the notation variables.<methodName>( <Parameter>).

get( String variableName)

The method determines the value for the variable with the entered variable name. For variables with a multi-value, the values are returned in a list (collection).

getDisplayValue( String variableName)

The method determines the value for the variable with the entered variable name. An according conversion will take place here depending on the data type.

For variables with a multi-value, the converted values are returned in a string, separated by commas. If the data type of the variables is Number, the converted values are returned in a string, separated by semicolons.

Data typeActual valueReturned value
String"some value""some value"
Number1.23"1.23"
Identityidentity:///identityprovider/scim/users/userIdOfJohnSmith

"John Smith" (displayName-property of the user,

name-property for groups in the d.ecs identity provider)

DmsObjectdmsObject:///dms/r/someRepo/o2/T000000001"/dms/r/someRepo/o2/T000000001"

Generating multi-values

You can use the object collections to generate a list (collection) from individual values, e.g. to assign a multi-value to a variable. Generating a list from individual values is useful if you want to register several recipients as a constant in a user activity.

Example

${collections.from( "identity:///identityprovider/scim/users/user1", "identity:///identityprovider/scim/users/user")}


from( Object...objects)

The method generates a list (collection) with the transferred individual values.

Useful information on the scope of process variables

Process variables always have a specific scope within a process instance. Depending on the scope, read and write access will be possible.

In every process instance, there is a universal scope which comprises the entire process. All other scopes, such as user or service activities, have read access to the variables in the universal scope.

Additional scopes are generated at the following points:

  • Gateways with parallel paths
  • Multi-instance constructs
  • Subprocesses
  • Input/output mapping or timer events during user activities
  • Service activities

Read access

Read access to process variables (e.g. the use in an expression) is possible independently of the scope. If no value is found in the current scope, the section above it is searched until a value has been found.

Write access

If you want to change values (e.g. in a user activity with output mapping), the value is always applied to the current scope. Other scopes, e.g. along other branches in the process, are not impacted by this until the end of this scope. The changes are transferred to all other scopes only at the end of the current scope.

End of scopes

At the end of a scope (e.g. when joining parallel branches or at the end of a subprocess), the variables of this scope are discarded. You must configure an output mapping before you can apply variables to a scope located higher in the hierarchy. In the process, the call hierarchy is run through until a scope that already contains this variable is found. This run starts from the current item and works its way towards the top. The new value is then applied to this scope. If the variable is completely new, it is then written to the scope of the entire process.

Please note that a timer event generates its own scope during user activities. If you do not define a dedicated input/output mapping for the user activity, all variables of this scope will be applied to the higher scope when the activity is completed.


Impact on process monitoring

The view of a token always shows the variables of the current scope. Changes to the variables are only applied in this scope.

Most tokens have their own scope. The only exception are user activities for which no input/output mapping was configured and which are not executed in parallel to other activities. Theses tokens have the same scope as the token directly above them.

In the view of the token without its own scope, you can find a link to a token from the section above it. When you select this link, you can view the variables of the linked scope.

Using timer events

For process modeling, you can use the BPMN item intermediate boundary event (attached intermediate event) of the Timer type. You can attach these intermediate events to user activities or services. When getting started with attached intermediate events, it is useful to create a simple process with one user activity first.

The BPMN model of this sample process is structured as follows:

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" targetNamespace="">
  <process id="timer_event_process" name="Timer Event Process" isExecutable="true">
    <startEvent id="start" />     
	<userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
  </process>
</definitions>

Adding an intermediate event

Add the BPMN item boundaryEvent to the process. 

...
<process id="timer_event_process" name="Timer Event Process" isExecutable="true">
  ...
  <userTask ... />
  <boundaryEvent id="timer" attachedToRef="task_hello_world">
    <timerEventDefinition>
      <timeDuration>PT1M</timeDuration>
    </timerEventDefinition>
  </boundaryEvent>
  ...
</process>

Explanation of the properties

  • id:The property is used as a unique identifier for the send activity.
  • attachedToRef: The property defines which BPMN item this intermediate event should be attached to.

Explanation of the event definition:

  • timerEventDefinition: This BPMN item defines that the intermediate event is a time event
  • timeDuration: This BPMN item defines that it is a relative time span. In this case, a span of one minute has been defined. If you want to define an absolute point in time, you can use the BPMN item timeDate. In both cases, you need to enter the values in the ISO 8601 format. You can also determine the values from variables.

Adding an event path

If an intermediate event occurs in the process, the process follows a separate process path. You can e.g. configure a process in such a way that the process leads from an intermediate event directly to the end event. You insert this configuration into the process as follows:

...
<process id="timer_event_process" name="Timer Event Process" isExecutable="true">
  ...
  <sequenceFlow id="s3" sourceRef="timer" targetRef="end" />
</process>

The BPMN diagram was extended by diagram information so that the diagram can be displayed correctly in the modeling tool as well as in the user interface. The final BPMN definition looks as follows:

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" targetNamespace="">
  <process id="timer_event_process" name="Timer Event Process" isExecutable="true">
    <startEvent id="start" />
    <userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />
    <boundaryEvent id="timer" attachedToRef="task_hello_world">
      <timerEventDefinition>
        <timeDuration>PT1M</timeDuration>
      </timerEventDefinition>
    </boundaryEvent>
    <endEvent id="end" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
    <sequenceFlow id="s3" sourceRef="timer" targetRef="end" />
  </process>
      
  <!-- Diagram information -->
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="timer_event_process">
      <bpmndi:BPMNShape id="start_di" bpmnElement="start">
        <dc:Bounds x="179" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="task_hello_world_di" bpmnElement="task_hello_world">
        <dc:Bounds x="290" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="timer_di" bpmnElement="timer">
        <dc:Bounds x="372" y="139" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="end_di" bpmnElement="end">
        <dc:Bounds x="462" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="s1_di" bpmnElement="s1">
        <di:waypoint x="215" y="117" />
        <di:waypoint x="290" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="s2_di" bpmnElement="s2">
        <di:waypoint x="390" y="117" />
        <di:waypoint x="462" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="s3_di" bpmnElement="s3">
        <di:waypoint x="408" y="157" />
        <di:waypoint x="480" y="157" />
        <di:waypoint x="480" y="135" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Using gateways

When modeling your own processes, you can use the BPMN item Gateway of the exclusive type (branching point of exclusive type) to create dynamic processes with a decision logic.

When getting started with exclusive gateways, it is useful to create a simple process with one user activity first. This process will e.g. look like this:



The BPMN model of this sample process is structured as follows:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" targetNamespace="">
  <process id="exclusive_gateway_process" name="Exclusive Gateway Process" isExecutable="true">
    <startEvent id="start" />     
	<userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />
    <endEvent id="end" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
  </process>
</definitions>

You now expand this sample process with a gateway. Based on the value of a process variable, this process will either lead to the user activity or will be ended directly.

Adding a gateway

First add the BPMN item exclusiveGateway to the process. The item exclusiveGateway represents a branching point with only one possible start path. Then replace the existing sequence flows with the following sequence flows:

...
<process id="exclusive_gateway_process" name="Exclusive Gateway Process" isExecutable="true">
  <startEvent id="start" />
  <exclusiveGateway id="gateway" default="gateway-option-b" />   
  <userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />
  <exclusiveGateway id="join" />
  <endEvent id="end" />
  <sequenceFlow id="s1" sourceRef="start" targetRef="gateway" />
  <sequenceFlow id="gateway-option-a" sourceRef="gateway" targetRef="task_hello_world" />
  <sequenceFlow id="gateway-option-b" sourceRef="gateway" targetRef="join" />
  <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="join" />
  <sequenceFlow id="s3" sourceRef="join" targetRef="end" />
</process>

Explanation of the properties:

  • id: The property is used as a unique identifier for the gateway.
  • default: The property defines the ID of the sequence flow to be selected as the default start path of the gateway.

The process will then e.g. look like this:

Adding a condition

All start paths of an exclusive gateway must contain a condition. The application uses this condition to determine which path the process is to take. For the sample process, add the condition to the sequence flow gw-option-a that this path is selected depending on the variable amount. If this variable corresponds to a value greater than 1000, the sequence flow gw-option-a is to be selected.

...
<sequenceFlow id="gw-option-a" sourceRef="gateway" targetRef="task_hello_world" > 
  <conditionExpression xsi:type="tFormalExpression">${variables.get("amount") > 1000}</conditionExpression>
<sequenceFlow>
...

To be able to use a process variable, you need to add it to the process definition. In the process definition, you add the BPMN items extensionElements and camunda:properties to the BPMN item process. To define the process variable, then add the item camunda:property to the BPMN item camunda:properties. In this example, you add the variable amount of the Number type. This is a mandatory variable which must be provided at the start.

...
<process id="exclusive_gateway_process" name="Exclusive Gateway Process" isExecutable="true">
  <extensionElements>
    <camunda:properties>
      <camunda:property name="variable:amount*" value="Number!" />
    </camunda:properties>
  </extensionElements>
  ...
</process>

The BPMN diagram was extended by diagram information so that the diagram can be displayed correctly in the modeling tool as well as in the user interface. The final BPMN definition looks as follows:

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" targetNamespace="">
  <process id="exclusive_gateway_process" name="Exclusive Gateway Process" isExecutable="true">
    <extensionElements>
      <camunda:properties>
        <camunda:property name="variable:amount*" value="Number!" />
      </camunda:properties>
    </extensionElements>
    <startEvent id="start" />
    <exclusiveGateway id="gateway" default="gateway-option-b" />
    <userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />
    <exclusiveGateway id="join" />
    <endEvent id="end" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="gateway" />
    <sequenceFlow id="gateway-option-a" sourceRef="gateway" targetRef="task_hello_world">
      <conditionExpression xsi:type="tFormalExpression">${variables.get("amount") > 1000}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="gateway-option-b" sourceRef="gateway" targetRef="join" />
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="join" />
    <sequenceFlow id="s3" sourceRef="join" targetRef="end" />
  </process>
  
  <!-- Diagram information -->
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="exclusive_gateway_process">
      <bpmndi:BPMNShape id="start_di" bpmnElement="start">
        <dc:Bounds x="179" y="199" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="gateway_di" bpmnElement="gateway" isMarkerVisible="true">
        <dc:Bounds x="275" y="192" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="task_hello_world_di" bpmnElement="task_hello_world">
        <dc:Bounds x="410" y="80" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="join_di" bpmnElement="join" isMarkerVisible="true">
        <dc:Bounds x="595" y="192" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="end_di" bpmnElement="end">
        <dc:Bounds x="702" y="199" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="s1_di" bpmnElement="s1">
        <di:waypoint x="215" y="217" />
        <di:waypoint x="275" y="217" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="gateway-option-a_di" bpmnElement="gateway-option-a">
        <di:waypoint x="300" y="192" />
        <di:waypoint x="300" y="120" />
        <di:waypoint x="410" y="120" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="gateway-option-b_di" bpmnElement="gateway-option-b">
        <di:waypoint x="325" y="217" />
        <di:waypoint x="595" y="217" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="s2_di" bpmnElement="s2">
        <di:waypoint x="510" y="120" />
        <di:waypoint x="620" y="120" />
        <di:waypoint x="620" y="192" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="s3_di" bpmnElement="s3">
        <di:waypoint x="645" y="217" />
        <di:waypoint x="702" y="217" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

You can now define the value of the variable amount e.g. for the start of the process and impact the process sequence this way.

Inserting user activities

In this topic, you will find basic information on the use and customization of the BPMN item User Task (user activity).

Useful information on user activities

The BPMN standard includes two different constructs for the use of the BPMN item User Task (user activity). The constructs differ in that there is either one or potentially several recipients for an activity.

State an individual recipient as a Human Performer. If you are planning several recipients for an activity, use the Potential Owner construct. State several recipients as an array of identities (variable).

Example for an individual recipient

Human Performer
<userTask id='theTask' name='important task' >
    <humanPerformer>
      <resourceAssignmentExpression>
        <formalExpression>${variables.get("myPerformer")}</formalExpression>
      </resourceAssignmentExpression>
    </humanPerformer>
  </userTask>

Example for several recipients

Potential Owner
<userTask id='theTask' name='important task' >
    <potentialOwner>
      <resourceAssignmentExpression>
        <formalExpression>${variables.get("myPotentialOwners")}</formalExpression>
      </resourceAssignmentExpression>
    </potentialOwner>
  </userTask>

Note

In camunda modeler, the Potential Owner construct is mapped by the fields Candidate Users and Candidate Groups.

Potential Owner
<userTask id='theTask' name='important task' camunda:candidateUsers="${variables.get('myPotentialOwners')}" />

You can now use the Human Performer construct using the field Assignee. You can only state one user in this field.

Human Performer
<userTask id='theTask' name='important task' camunda:assignee="${variables.get('myPerformer')}" />

Using constants for recipients

If you want to state the recipient of an activity as a constant, use the following syntax:

identity:///identityprovider/scim/users/someUserId
// or
${collections.from("identity:///identityprovider/scim/users/someUserId", "identity:///identityprovider/scim/users/someOtherUserId")} 

Using variables for recipients

If the recipients of an activity are to determined from variables, use the following syntax to reference the variables:

${variables.get("variableName")}

Linking additional information to user activities

To add additional information to user activities for processing, you can use the process variable dv_attachment reserved for this purpose.

You can save one URL in this variable. The URL is added during the creation of an activity if you have entered it beforehand.

Important

The process variable dv_attachment is predefined with the data type DmsObject. If you want to use a different URI than that for an object of the DMS app, you need to change the value of the data type to String.

Adding metadata to user activities

You can define metadata within the BPMN item userTask in order to add this metadata to user activities. Add the item extensionElements and, under it, the item camunda:properties if the process definition does not contain these items yet. You can now define metadata as follows below the item camunda:properties:

<userTask>
...
	<extensionElements>
		<camunda:properties>
			<camunda:property name="metadata:invoiceNumber:value" value="${variables.get("invoiceNumber")}" />
          	<camunda:property name="metadata:invoiceNumber:caption" value="Invoice Number" />
          	<camunda:property name="metadata:invoiceNumber:caption:de" value="Rechnungsnummer" />
		</camunda:properties>
	</extensionElements>
...
</userTask>


The property name within the item camunda:property can accept the following values:

ValueMeaning
metadata:<key>:valueDefines the value of a metadata item. 

The key of the metadata item must correspond to the following expression: [A-Za-z0-9]{1,255}


metadata:<key>:captionDefines the standard designation of a metadata item (optional).
If it does not exist, the key is used as the designation.
metadata:<key>:caption:<language>Defines the designation of a metadata item for the language specified (optional). The language code must consist of two letters pursuant to the ISO 639-1 standard.
If it does not exist, the standard designation or key is used.

The property value can contain either a fixed value or an expression. This value can be a maximum of 255 characters long. When an expression is used, this restriction applies to the result of the expression. In addition, the result of an expression must be an individual value. Values of the type Collection or Array are not permitted.

Determining the storage duration of a user activity

You can define the storage duration of user activities within the BPMN item userTask. Add the item extensionElements and, under it, the item camunda:properties if the process definition does not contain these items yet. You can now define the storage duration as follows under the item camunda:properties.

<userTask>
...
	<extensionElements>
		<camunda:properties>
			<camunda:property name="retentionTime" value="P7D" />
		</camunda:properties>
	</extensionElements>
...
</userTask>

The property value can contain either a fixed value or an expression. Define the storage duration as a period of time in days pursuant to ISO 8601, for example, P30D for 30 days.

Adding user interfaces to a user activity

When you use the BPMN item User Task (user activity) for the creation of a process model, you can add a user interface to the activity. The user will then e.g. be shown a button which he/she can use to start a task.

To add a user interface, use the property formKey.

Example

Form Key
<userTask id="someTask" camunda:formKey="uri:/myapp/myform">
  ...
</userTask>

The key consists of a prefix and a value. These are separated by a colon. The following prefixes can be used:

Prefix

Meaning

Example

uriThe user interface is indicated using a URI.uri:https://example.com/

Using process variables

The key can also contain process variables. These can be indicated in the form of Expression Language.

Example

uri:${variables.get("formUri")}

uri:https://example.com/?queryParam=${variables.get("formParam")}

External access to process variables

You can use the expression ${process.task.variablesUri} to generate a URI in order to permit an external application to access the current variables of this user interface. You can use the HTTP methods GET and PUT to read and change these variables. In this user interface, an input and output mapping needs to be defined for the variables used.

Example

uri:/myApp?variablesUri=${process.task.variablesUri}


Using process variables in a user interface

If a user activity contains a form, you have read and write access via HTTP to the process variables used.

When getting started with process variables in a form, it is useful to create a simple process with one user activity first. This process will e.g. look like this:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" targetNamespace="">
  <process id="GettingStarted" name="Example: Getting started" isExecutable="true">
    <startEvent id="start"/>
    <userTask id='task_hello_world' name='Hello World' camunda:assignee="${variables.get('dv_initiator')}" />
    <endEvent id="end"/>       
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
  </process> 
</definitions>

To simplify the example, the graphic information on the BPMN diagram is not included in this BPMN sample file.

Creating a form

First create an HTML file. This may look as follows. The code examples are based on the functionality in Google Chrome. Other browsers may require different syntax.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Getting started</title>
</head>
<body/>    
</html>

Store the HTML file so that it is accessible by an HTTP gateway. Add the URI of the HTML document to the BPMN item userTask .

...
<process id="GettingStarted" name="Example: Getting started" isExecutable="true">
	...
    <userTask id='task_hello_world' name='Hello World' camunda:formKey="uri:/res/process/process-form.html?variables=${process.task.variablesUri}" camunda:assignee="${variables.get('dv_initiator')}" />
    ...

Explanation of the property

  • camunda:formKey: This property defines the URI which deploys the user interface for the user activity. The prefix uri: is mandatory here. The variable ${process.task.variablesUri} is appended to the URI as a query parameter. The variable is resolved by the application during runtime into a URI which deploys an HTTP endpoint for reading and writing of the variables.

Creating the user interface

First create the basic structure for an HTML table in your HTML document. Over the further course, the variables will then be displayed in this table.

...
<body>
    <table id="variables">
		<thead>
			<tr>
				<th>Name</th>
				<th>Value</th>
			</tr>
		</thead>
		<tbody id="variableValues">
		</tbody>
	</table>
</body>
...

Querying the process variables

In the head of the HTML document, you create a function for reading the process variables. The process variables are queried by the application using an HTTP GET request according to the REST API. Loading the variables is initiated by the event onLoad of the item body.

...
<head>
	...
	<script type="text/javascript">
	
		var urlParams = new URLSearchParams(window.location.search);
		var variablesUri = urlParams.get('variables');
			
		function loadVariables() {
			fetch(variablesUri)
				.then(response => response.json());
		}		
		
	</script>
</head>
<body onload="loadVariables()">
...

After the variables have been loaded, you can now view them in the prepared table. The following example uses the JavaScript library jQuery. Add the library jQuery in the head of the HTML document and implement suitable methods to view the variables.

...
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
	<script type="text/javascript">
	
		var urlParams = new URLSearchParams(window.location.search);
		var variablesUri = urlParams.get('variables');
			
		function loadVariables() {
			fetch(variablesUri)
				.then(response => response.json())
				.then(json => createTableFromVariables(json.variables || {}));
		}	
	
		function createTableFromVariables(variables) {
			Object.keys(variables).forEach(variable => {
				var value = variables[variable];
				$('#variableValues').append( `<tr class="variable">${createKeyColumn(variable)}${createValueColumn(value)}</tr>`);
			});
		}
		
		function createKeyColumn(variable) {
			return `<td><span class="key">${variable}</span></td>`;
		}
		
		function createValueColumn(value) {
			return `<td><input class="value" type="text" value="${value}"></td>`;
		}

	</script>
</head>
<body onload="loadVariables()">
...
	

The variables are now queried and displayed after the HTML document has been loaded.

Writing the process variables

Add methods to the script section which enable writing the variables back into the application. Then add a button below the table which calls the method saveVariables.

...
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
	<script type="text/javascript">
	
		var urlParams = new URLSearchParams(window.location.search);
		var variablesUri = urlParams.get('variables');
			
		...
		
		function saveVariables() {
			var variables = createVariablesFromTable();
			
			const headers = new Headers();
			headers.append('Cache-Control', 'no-cache');
			headers.append('Content-Type', 'application/json');

			let promise = fetch(variablesUri, {
				method: 'PUT',
				headers: headers,
				credentials: 'same-origin',
				body: JSON.stringify({variables})
			});

			promise.then(function(response) {
				let status = response.status;
				if (status !== 200 ) {
					window.alert("Saving variables failed: " + status);
				} else {
					window.alert("Variables saved");
				}
				
			});
		}

		function createVariablesFromTable() {
			var variables = {};
			$("tr.variable").each(function() {
				$this = $(this);
				var key = $this.find("span.key").html();
				var value = $this.find("input.value").val();
				variables[key] = value;
			});
			return variables;
		}

	</script>
</head>
<body onload="loadVariables()">
	...
	<br/>
	<button onClick="saveVariables()">Save</button>
</body>

You can use the form displayed on execution of the process to view and change the current process variables.

The final HTML document will look as follows. The HTML document contains several complementary CSS definitions for optimized display of the user interface items.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Process Form</title>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
	<style>
		table {
		  border-collapse: collapse;
		  width: 100%;
		}
		
		table, th, td {
		  border: 1px solid black;
		}
		
		td {
		  padding: 3px;
		}
		
		.key {
			color: gray;
		}
		
		th {
		  text-align: left;
		}
		
		input {
			width: 100%;
			border: 0;
		}
	</style>
    <script type="text/javascript">
	
		var urlParams = new URLSearchParams(window.location.search);
		var variablesUri = urlParams.get('variables');
			
		function loadVariables() {
			fetch(variablesUri)
				.then(response => response.json())
				.then(json => createTableFromVariables(json.variables || {}));
		}
		
		function saveVariables() {
			var variables = createVariablesFromTable();
			
			const headers = new Headers();
			headers.append('Cache-Control', 'no-cache');
			headers.append('Content-Type', 'application/json');

			let promise = fetch(variablesUri, {
				method: 'PUT',
				headers: headers,
				credentials: 'same-origin',
				body: JSON.stringify({variables})
			});

			promise.then(function(response) {
				let status = response.status;
				if (status !== 200 ) {
					window.alert("Saving variables failed: " + status);
				} else {
					window.alert("Variables saved");
				}
				
			});
		}
		
		function createTableFromVariables(variables) {
			Object.keys(variables).forEach(variable => {
				var value = variables[variable];
				$('#variableValues').append( `<tr class="variable">${createKeyColumn(variable)}${createValueColumn(value)}</tr>`);
			});
		}
		
		function createKeyColumn(variable) {
			return `<td><span class="key">${variable}</span></td>`;
		}
		
		function createValueColumn(value) {
			return `<td><input class="value" type="text" value="${value}"></td>`;
		}
		
		function createVariablesFromTable() {
			var variables = {};
			$("tr.variable").each(function() {
				$this = $(this);
				var key = $this.find("span.key").html();
				var value = $this.find("input.value").val();
				variables[key] = value;
			});
			return variables;
		}
		
	</script>
</head>
<body onload="loadVariables()">
    <table id="variables">
		<thead>
			<tr>
				<th>Name</th>
				<th>Value</th>
			</tr>
		</thead>
		<tbody id="variableValues">
		</tbody>
	</table>
	<br/>
	<button onClick="saveVariables()">Save</button>
</body>
</html>

Using a multi-instance

You can add multiple executions to user activities and subprocesses. This requires that the activity or the process is based on a multi-value variable. The activity is executed once for each value of the variable. 

When getting started with multi-instances, it is useful to create a simple process with one user activity first. This process will e.g. look like this:

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" targetNamespace="">
  <process id="multi_instance_process" name="Multi Instance Process" isExecutable="true">
    <startEvent id="start" />     
	<userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />   
    <endEvent id="end" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
  </process>
</definitions>

Adding a multi-instance

Add the BPMN item multiInstanceLoopCharacteristics to the user activity. Then change the variable which defines the recipient of the user activity to myPerformer.

...
<process id="multi_instance_process" name="Multi Instance Process" isExecutable="true">
  ...   
  <userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('myPerformer')}" >
      <multiInstanceLoopCharacteristics
          isSequential="false"
          camunda:collection="${variables.get('performers')}"
          camunda:elementVariable="myPerformer" />
  </userTask>
  ...
</process>

Explanation of the properties

  • isSequential: Use the value true to execute the activities sequentially and false to execute them simultaneously.
  • camunda:collection: Expression returning a multi-variable.
  • camunda:elementVariable: Variable name used locally for the respective value. A definition must be available for the variable.

In the sample process, an activity is sent for each value of the variable performers . The local variable myPerformer can be used to indicate that each individual item is a recipient.

In order to be able to use the variables performers and myPerformer, you need to define them. Add the BPMN items extensionElements and camunda:properties to the BPMN items process and userTask . To define the process variables, then add the item camunda:property to each of the BPMN items camunda:properties.

...
<process id="multi_instance_process" name="Multi Instance Process" isExecutable="true">
  <extensionElements>
    <camunda:properties>
      <camunda:property name="variable:performers*" value="[Identity]!" />
    </camunda:properties>
  </extensionElements>
  ...   
  <userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('myPerformer')}" >
     <extensionElements>
      <camunda:properties>
        <camunda:property name="variable:myPerformer" value="Identity" />
      </camunda:properties>
    </extensionElements>
  ...
</process>

The BPMN diagram was extended by diagram information so that the diagram can be displayed correctly in the modeling tool as well as in the user interface. The final BPMN definition looks as follows:

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" targetNamespace="">
  <process id="multi_instance_process" name="Multi Instance Process" isExecutable="true">
    <extensionElements>
      <camunda:properties>
        <camunda:property name="variable:performers*" value="[Identity]!" />
      </camunda:properties>
    </extensionElements>
    <startEvent id="start" />
    <userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('myPerformer')}" >
      <extensionElements>
        <camunda:properties>
          <camunda:property name="variable:myPerformer" value="Identity" />
        </camunda:properties>
      </extensionElements>
      <multiInstanceLoopCharacteristics
            isSequential="false"
            camunda:collection="${variables.get('performers')}"
            camunda:elementVariable="myPerformer" />
    </userTask>
    <endEvent id="end" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
  </process>
    
  <!-- Diagram information -->
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="multi_instance_process">
      <bpmndi:BPMNShape id="start_di" bpmnElement="start">
        <dc:Bounds x="179" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="task_hello_world_di" bpmnElement="task_hello_world">
        <dc:Bounds x="290" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="end_di" bpmnElement="end">
        <dc:Bounds x="462" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="s1_di" bpmnElement="s1">
        <di:waypoint x="215" y="117" />
        <di:waypoint x="290" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="s2_di" bpmnElement="s2">
        <di:waypoint x="390" y="117" />
        <di:waypoint x="462" y="117" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

You can now define the value of the variable performers e.g. for the start of the process.

Using escalations

When modeling your own processes, you can use escalations to influence the process flow. When you start using escalations, it is useful to create a simple process with one user activity and one timer event first. This process will e.g. look like this:


The BPMN model of this sample process is structured as follows:

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" targetNamespace="">
  <process id="escalation_process" name="Escalation Process" isExecutable="true">
    <startEvent id="start" />
    <userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />  
    <boundaryEvent id="timer" attachedToRef="task_hello_world">
      <timerEventDefinition>
        <timeDuration>PT1M</timeDuration>
      </timerEventDefinition>
    </boundaryEvent>
    <endEvent id="end" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
    <sequenceFlow id="s3" sourceRef="timer" targetRef="end" />
  </process>
</definitions>

We now want to modify this sample process so an escalation is triggered when a timer event occurs. The escalation will then start a subprocess that describes the escalation path. First, you need to create an escalation object for this modification.

Adding an escalation object

First add the BPMN item escalation

...
<definitions ...>
  <process id="escalation_process" name="Escalation Process" isExecutable="true">
    ...
  </process>
  <escalation id="time_escalation" name="Time Escalation" escalationCode="123" />
</definitions>

Explanation of the properties:

  • id:The property is used as a unique identifier for the escalation.
  • name: The display name of the escalation.
  • escalationCode: The property defines a technical code that can be used on items waiting for escalations in order to identify the triggering escalation.

Now the escalation can be used in the BPMN item IntermediateThrowEvent or an EndEvent in order to trigger a corresponding escalation event.

Adding an escalation event

First add the BPMN item IntermediateThrowEvent with an EscalationEventDefinition element to the process. Then change the target of the sequence flow s3 running from end to throw_time_escalation, and then add a new sequence flow s4 running from throw_time_escalation to end.

...
<process id="escalation_process" name="Escalation Process" isExecutable="true">
  ...
  <intermediateThrowEvent id="throw_time_escalation">
    <escalationEventDefinition escalationRef="time_escalation" />
  </intermediateThrowEvent>
  <endEvent id="end" />
  ...
  <sequenceFlow id="s3" sourceRef="timer" targetRef="throw_time_escalation" />
  <sequenceFlow id="s4" sourceRef="throw_time_escalation" targetRef="end" />
</process>
<escalation id="time_escalation" name="Time Escalation" escalationCode="123" />
...

This is what the process now looks like:


Adding an escalation path

Now add a subprocess whose BPMN item StartEvent contains the item EscalationEventDefinition.

...
<process id="escalation_process" name="Escalation Process" isExecutable="true">
  <extensionElements>
    <camunda:properties>
      <camunda:property name="variable:escalationCode" value="String" />
    </camunda:properties>
  </extensionElements>
  <startEvent id="start" />
  ...
  <sequenceFlow id="s4" sourceRef="throw_time_escalation" targetRef="end" />
  <subProcess id="escalation_subprocess" name="Escalation Process" triggeredByEvent="true">
    <startEvent id="sub_start" isInterrupting="false">
      <escalationEventDefinition escalationRef="time_escalation" camunda:escalationCodeVariable="escalationCode" />
    </startEvent>
    <endEvent id="sub_end" />
    <sequenceFlow id="sub_s1" sourceRef="sub_start" targetRef="sub_end" />
  </subProcess>
</process> 
<escalation id="time_escalation" name="Time Escalation" escalationCode="123" />
...

Explanation of the properties:

  • subProcess
    • triggeredByEvent: It must contain the value true. The property specifies that the start event of this subprocess is triggered by an event (an escalation event in this case).
    • isInterrupting: If it is true, the process branch that triggered the escalation is terminated. If it is false, the process branch continues to run in parallel.
  • escalationEventDefinition
    • escalationRef: Contains the ID of the escalation that is to be used to trigger this event.
    • camunda:escalationCodeVariable: (optional) name of the variables in which the value of escalationCode of the occurring escalation is to be saved (variable must be defined).

Note that when you use the property camunda:escalationCodeVariable, you also need to add a definition of the corresponding process variables in the main process.

Now add an additional user activity that should be run in the event of an escalation. 

...
<process id="escalation_process" name="Escalation Process" isExecutable="true">
  ...
  <subProcess id="escalation_subprocess" name="Escalation Process" triggeredByEvent="true">
    <startEvent id="sub_start" isInterrupting="false">
      <escalationEventDefinition escalationRef="time_escalation" camunda:escalationCodeVariable="escalationCode" />
    </startEvent>       
	<userTask id="sub_task_escalation" name="Escalation occurred" camunda:assignee="${variables.get('dv_initiator')}" />
    <endEvent id="sub_end" />
    <sequenceFlow id="sub_s1" sourceRef="sub_start" targetRef="sub_task_escalation" />
    <sequenceFlow id="sub_s2" sourceRef="sub_task_escalation" targetRef="sub_end" />
  </subProcess>
</process> 
<escalation id="time_escalation" name="Time Escalation" escalationCode="123" />
...

For reasons of simplification, the user that started the process is entered as the recipient of the user activity of the escalation path.

This is what the final process looks like:

The BPMN diagram was extended by diagram information so that the diagram can be displayed correctly in the modeling tool as well as in the user interface. The final BPMN definition looks as follows:

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI"  xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" targetNamespace="">
  <process id="escalation_process" name="Escalation Process" isExecutable="true">
    <extensionElements>
      <camunda:properties>
        <camunda:property name="variable:escalationCode" value="String" />
      </camunda:properties>
    </extensionElements>

    <startEvent id="start" />
    <userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />    
    <boundaryEvent id="timer" attachedToRef="task_hello_world">
      <timerEventDefinition>
        <timeDuration>PT1M</timeDuration>
      </timerEventDefinition>
    </boundaryEvent>
    <intermediateThrowEvent id="throw_time_escalation">
      <escalationEventDefinition escalationRef="time_escalation" />
    </intermediateThrowEvent>
    <endEvent id="end" />

    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
    <sequenceFlow id="s3" sourceRef="timer" targetRef="throw_time_escalation" />
    <sequenceFlow id="s4" sourceRef="throw_time_escalation" targetRef="end" />

    <subProcess id="escalation_subprocess" name="Escalation Process" triggeredByEvent="true">
      <startEvent id="sub_start" isInterrupting="false">
        <escalationEventDefinition escalationRef="time_escalation" camunda:escalationCodeVariable="escalationCode" />
      </startEvent>
      <userTask id="sub_task_escalation" name="Escalation occurred" camunda:assignee="${variables.get('dv_initiator')}" />
      <endEvent id="sub_end" />
      <sequenceFlow id="sub_s1" sourceRef="sub_start" targetRef="sub_task_escalation" />
      <sequenceFlow id="sub_s2" sourceRef="sub_task_escalation" targetRef="sub_end" />
    </subProcess>

  </process>
  <escalation id="time_escalation" name="Time Escalation" escalationCode="123" />

  <!-- Diagram information -->
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="escalation_process">
      <bpmndi:BPMNShape id="start_di" bpmnElement="start">
        <dc:Bounds x="179" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="task_hello_world_di" bpmnElement="task_hello_world">
        <dc:Bounds x="290" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="timer_di" bpmnElement="timer">
        <dc:Bounds x="372" y="139" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="throw_time_escalation_di" bpmnElement="throw_time_escalation">
        <dc:Bounds x="432" y="202" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="end_di" bpmnElement="end">
        <dc:Bounds x="492" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="s1_di" bpmnElement="s1">
        <di:waypoint x="215" y="117" />
        <di:waypoint x="290" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="s2_di" bpmnElement="s2">
        <di:waypoint x="390" y="117" />
        <di:waypoint x="492" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="s3_di" bpmnElement="s3">
        <di:waypoint x="390" y="175" />
        <di:waypoint x="390" y="220" />
        <di:waypoint x="432" y="220" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="s4_di" bpmnElement="s4">
        <di:waypoint x="468" y="220" />
        <di:waypoint x="510" y="220" />
        <di:waypoint x="510" y="135" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="escalation_subprocess_di" bpmnElement="escalation_subprocess" isExpanded="true">
        <dc:Bounds x="165" y="290" width="350" height="200" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="sub_start_di" bpmnElement="sub_start">
        <dc:Bounds x="205" y="372" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="sub_task_escalation_di" bpmnElement="sub_task_escalation">
        <dc:Bounds x="290" y="350" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="sub_end_di" bpmnElement="sub_end">
        <dc:Bounds x="442" y="372" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="sub_s1_di" bpmnElement="sub_s1">
        <di:waypoint x="241" y="390" />
        <di:waypoint x="290" y="390" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="sub_s2_di" bpmnElement="sub_s2">
        <di:waypoint x="390" y="390" />
        <di:waypoint x="442" y="390" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>


Using services

In this topic, you will find out how to embed services in your processes. When inserting services, you can decide whether the service will be executed synchronously or asynchronously.

Using a synchronous service

Automated activities are executed in a process by means of services. For the use of synchronous services in BPMN, you can use the BPMN item Send Task (send activity). When the process reaches the send activity, the data defined in the process are sent to the HTTP endpoint of the service provider and immediately wait for the result. The process execution is then continued directly. Using a simple service example, this item shows you how you can use a synchronous service. The service example "Hello World" changes any text to "Hello <yourname>" where <yourname> is the text which was sent to the service beforehand.

To execute this example, it is useful to create a simple process with one user activity first. The BPMN model of this sample process is structured as follows:

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" targetNamespace="">
  <process id="sync_service_process" name="Sync Service Process" isExecutable="true">
    <startEvent id="start" />
    <userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />    
    <endEvent id="end" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
  </process> 
</definitions>

Adding a send activity

First add a send activity after the start event. 

...
<process id="sync_service_process" name="Sync Service Process" isExecutable="true">
  <startEvent id="start" />
  <sendTask id="call_service"
        name="Call Service 'Hello World'"
        camunda:asyncBefore="true"
	    camunda:asyncAfter="true"
        camunda:delegateExpression="${syncService}"
        camunda:exclusive="true">
  </sendTask>
  ...
</process>

Explanation of the properties:

  • id: The property is used as a unique identifier for the send activity.
  • name: This property is used as a display name in the user interfaces.
  • camunda:*: These properties contain technical information required for the execution.

    Note

    For synchronous services, you always need to enter the values of the example for the camunda properties. If you enter different values, the process cannot be deployed.

Now add the BPMN items extensionElements and camunda:inputOutput to the send activity. You need to define all data which are to be sent to the HTTP endpoint of the service. To define the data, add the BPMN item camunda:inputParameter to the process definition for each value. Next you also need to define the expected output values. To do so, add the BPMN item camunda:outputParameter to the process definition for each value.

...
<process id="sync_service_process" name="Sync Service Process" isExecutable="true">
  <startEvent id="start" />
  <sendTask id="call_service" ...>
    <extensionElements>
      <camunda:inputOutput>
        <camunda:inputParameter name="service.uri">/process/services/helloworld/sync</camunda:inputParameter>
        <camunda:inputParameter name="yourName">${variables.getDisplayValue("dv_initiator")}</camunda:inputParameter>
        <camunda:outputParameter name="greeting">${variables.get("greeting")}</camunda:outputParameter>
      </camunda:inputOutput>
    </extensionElements>
  </sendTask>
  ...
</process>

Explanation of the parameters:

  • service.uri: This parameter must always be inserted. It defines the URI used to reach the HTTP endpoint of the service. The example shows the URI of the service "Hello World". The value of this variable must be a constant, i.e. it must not contain any expressions.
  • yourName: This parameter was defined as an input value by the specific service. This example uses the view name of the user who has started the process. 
  • greeting: The service has defined the parameter greeting as the only output value. This parameter is automatically written to a variable of the same name in the scope of the send activity when the service responds. The parameter defines that the content of this result value is written into the variable greeting in the scope of the entire process when the process is continued. 

To enable the communication between the application and the service, you need to add the interface of the service to the process. To add the interface, enter the BPMN items extensionElements and camunda:properties in the process definition. Then add one BPMN item camunda:property each for the service input value yourName, the service output value greeting, as well as the resulting process variable greeting . All values are of data type String.

...
<process id="sync_service_process" name="Sync Service Process" isExecutable="true">
  <extensionElements>
    <camunda:properties>
      <camunda:property name="service:/process/services/helloworld/sync:in:yourName" value="String" />
      <camunda:property name="service:/process/services/helloworld/sync:out:greeting" value="String" />
      <camunda:property name="variable:greeting" value="String" />
    </camunda:properties>
  </extensionElements>
  ...
</process>

The variable greeting now contains the text "Hello <display name of process start user>". Now use this variable as the name of the user activity so that the user receives the friendly greeting as the subject of the task to complete. 

...
<process id="sync_service_process" name="Sync Service Process" isExecutable="true">
  ...
  <userTask id="task_hello_world" name="${variables.get('greeting')}" camunda:assignee="${variables.get('dv_initiator')}" />    
  ...
</process>

To ensure that the process activities are executed in the right sequence, you still need to adapt the sequence flow items to the new activities. 

<process id="sync_service_process" name="Sync Service Process" isExecutable="true">
  ...
  <sequenceFlow id="s1" sourceRef="start" targetRef="call_service" />
  <sequenceFlow id="s2" sourceRef="call_service" targetRef="task_hello_world" />
  <sequenceFlow id="s3" sourceRef="task_hello_world" targetRef="end" />
</process>

The BPMN diagram was extended by diagram information so that the diagram can be displayed correctly in the modeling tool as well as in the user interface. The final BPMN definition looks as follows:

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" targetNamespace="">
  <process id="sync_service_process" name="Sync Service Process" isExecutable="true">
    <extensionElements>
      <camunda:properties>
        <camunda:property name="service:/process/services/helloworld/sync:in:yourName" value="String" />
        <camunda:property name="service:/process/services/helloworld/sync:out:greeting" value="String" />
        <camunda:property name="variable:greeting" value="String" />
      </camunda:properties>
    </extensionElements>
    <startEvent id="start" />
    <sendTask id="call_service"
          name="Call Service 'Hello World'"
          camunda:asyncBefore="true"
          camunda:asyncAfter="true"
          camunda:delegateExpression="${syncService}"
          camunda:exclusive="true">
      <extensionElements>
        <camunda:inputOutput>
          <camunda:inputParameter name="service.uri">/process/services/helloworld/sync</camunda:inputParameter>
          <camunda:inputParameter name="yourName">${variables.getDisplayValue("dv_initiator")}</camunda:inputParameter>
          <camunda:outputParameter name="greeting">${variables.get("greeting")}</camunda:outputParameter>
        </camunda:inputOutput>
      </extensionElements>
    </sendTask>
    <userTask id="task_hello_world" name="${variables.get('greeting')}" camunda:assignee="${variables.get('dv_initiator')}" />      
    <endEvent id="end" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="call_service" />
    <sequenceFlow id="s2" sourceRef="call_service" targetRef="task_hello_world" />
    <sequenceFlow id="s3" sourceRef="task_hello_world" targetRef="end" />
  </process>
     
  <!-- Diagram information -->
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane" bpmnElement="sync_service_process">
      <bpmndi:BPMNShape id="start_di" bpmnElement="start">
        <dc:Bounds x="173" y="102" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="s1_di" bpmnElement="s1">
        <di:waypoint x="209" y="120" />
        <di:waypoint x="250" y="120" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="call_service_di" bpmnElement="call_service">
        <dc:Bounds x="250" y="80" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="s2_di" bpmnElement="s2">
        <di:waypoint x="350" y="120" />
        <di:waypoint x="390" y="120" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="task_hello_world_di" bpmnElement="task_hello_world">
        <dc:Bounds x="390" y="80" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="s3_di" bpmnElement="s3">
        <di:waypoint x="490" y="120" />
        <di:waypoint x="532" y="120" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="end_di" bpmnElement="end">
        <dc:Bounds x="532" y="102" width="36" height="36" />
      </bpmndi:BPMNShape>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Using an asynchronous service

Automated activities are executed in a process by means of services. For the use of asynchronous services in BPMN, you can use the BPMN items Send Task (send activity) and Receive Task (receive activity). When the process reaches the send activity, the data defined in the process are sent to the HTTP endpoint of the service provider. The process execution is then put on hold until the service provider returns the processing result. Using a simple service example, this item shows you how you can use an asynchronous service. The service example "Hello World" changes any text to "Hello <yourname>" where <yourname> is the text which was sent to the service beforehand.

To execute this example, it is useful to create a simple process with one user activity first. The BPMN model of this sample process is structured as follows:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" targetNamespace="">
  <process id="async_service_process" name="Async Service Process" isExecutable="true">
    <startEvent id="start" />
    <userTask id="task_hello_world" name="Hello World" camunda:assignee="${variables.get('dv_initiator')}" />
    <endEvent id="end" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="task_hello_world" />
    <sequenceFlow id="s2" sourceRef="task_hello_world" targetRef="end" />
  </process>
</definitions>

Adding a send activity

First add a send activity after the start event. 

...
<process id="async_service_process" name="Async Service Process" isExecutable="true">
  <startEvent id="start"/>
  <sendTask id="call_service"
        name="Call Service 'Hello World'"
        camunda:asyncBefore="true"
        camunda:delegateExpression="${asyncService}"
        camunda:exclusive="true">
  </sendTask>
  ...
</process>

Explanation of the properties:

  • id: The property is used as a unique identifier for the send activity.
  • name: This property is used as a display name in the user interfaces.
  • camunda:*: These properties contain technical information required for the execution.

    Note

    For asynchronous services, you always need to enter the values of the example for the camunda properties. If you enter different values, the process cannot be deployed.

Now add the BPMN items extensionElements and camunda:inputOutput to the send activity. You need to define all data which are to be sent to the HTTP endpoint of the service. To define the data, add the BPMN item camunda:inputParameter to the process definition for each value.

...
<process id="async_service_process" name="Async Service Process" isExecutable="true">
  <startEvent id="start"/>
  <sendTask id="call_service" ...>
    <extensionElements>
      <camunda:inputOutput>
        <camunda:inputParameter name="service.uri">/process/services/helloworld/async</camunda:inputParameter>
        <camunda:inputParameter name="yourName">${variables.getDisplayValue("dv_initiator")}</camunda:inputParameter>
      </camunda:inputOutput>
    </extensionElements>
  </sendTask>
  ...
</process>

Explanation of the parameters:

  • service.uri: This parameter must always be inserted. It defines the URI used to reach the HTTP endpoint of the service. The example shows the URI of the service "Hello World". The value of this variable must be a constant, i.e. it must not contain any expressions.
  • yourName: This parameter was defined as an input value by the specific service. This example uses the view name of the user who has started the process. 

Adding a receive activity

Now add the receive activity to the process definition. The receive activity is used to relay the processed data from the service to the process.

...
<process id="async_service_process" name="Async Service Process" isExecutable="true">
  ...
  </sendTask>
  <receiveTask id="receive_service_response"
        name="Wait for Service 'Hello World'"
        camunda:asyncAfter="true"
        camunda:exclusive="true">
  </receiveTask>
  ...
</process>

Explanation of the properties:

  • id: The property is used as a unique identifier for the send activity.
  • name: This property is used as a display name in the user interfaces.
  • camunda:*: These properties contain technical information required for the execution. For asynchronous services, you always need to enter the value true for the property camunda:asyncAfter.

Add the BPMN items extensionElements and camunda:inputOutput to the receive activity. You need to define all data which are expected as a response by the HTTP endpoint of the service. To define the data, insert the BPMN item camunda:outputParameter for each value.

...
<process id="async_service_process" name="Async Service Process" isExecutable="true">
  ...
  </sendTask>
  <receiveTask id="receive_service_response" ...>
    <extensionElements>
      <camunda:inputOutput>
        <camunda:outputParameter name="greeting">${variables.get("greeting")}</camunda:outputParameter>
      </camunda:inputOutput>
    </extensionElements>
  </receiveTask>
  ...
</process>

Explanation of the parameters:

  • greeting: The service has defined the parameter greeting as the only output value. This parameter is automatically written to a variable of the same name in the scope of the receive activity when the service responds. The parameter defines that the content of this result value is written into the variable greeting in the scope of the entire process when the process is continued. 

To enable the communication between the application and the service, you need to add the interface of the service to the process. To add the interface, enter the BPMN items extensionElements and camunda:properties in the process definition. Then add one BPMN item camunda:property each for the service input value yourName, the service output value greeting, as well as the resulting process variable greeting . All values are of data type String.

...
<process id="async_service_process" name="Async Service Process" isExecutable="true">
  <extensionElements>
    <camunda:properties>
      <camunda:property name="service:/process/services/helloworld/async:in:yourName" value="String" />
      <camunda:property name="service:/process/services/helloworld/async:out:greeting" value="String" />
      <camunda:property name="variable:greeting" value="String" />
    </camunda:properties>
  </extensionElements>
  ...
</process>

The variable greeting now contains the text "Hello <display name of process start user>". Now use this variable as the name of the user activity so that the user receives the friendly greeting as the subject of the task to complete. 

...
<process id="async_service_process" name="Async Service Process" isExecutable="true">
  ...
  <userTask id="task_hello_world" name="${variables.get('greeting')}" camunda:assignee="${variables.get('dv_initiator')}" />
  ...
</process>

To ensure that the process activities are executed in the right sequence, you still need to adapt the sequence flow items to the new activities. 

...
<process id="async_service_process" name="Async Service Process" isExecutable="true">
  ...
  <endEvent id="end" />
  <sequenceFlow id="s1" sourceRef="start" targetRef="call_service" />
  <sequenceFlow id="s2" sourceRef="call_service" targetRef="receive_service_response" />
  <sequenceFlow id="s3" sourceRef="receive_service_response" targetRef="task_hello_world" />
  <sequenceFlow id="s4" sourceRef="task_hello_world" targetRef="end" />
</process>

The BPMN diagram was extended by diagram information so that the diagram can be displayed correctly in the modeling tool as well as in the user interface. The final BPMN definition looks as follows: 

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI"  xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" targetNamespace="">
  <process id="async_service_process" name="Async Service Process" isExecutable="true">
    <extensionElements>
      <camunda:properties>
        <camunda:property name="service:/process/services/helloworld/async:in:yourName" value="String" />
        <camunda:property name="service:/process/services/helloworld/async:out:greeting" value="String" />
        <camunda:property name="variable:greeting" value="String" />
      </camunda:properties>
    </extensionElements>
    <startEvent id="start" />
    <sendTask id="call_service"
          name="Call Service 'Hello World'"
          camunda:asyncBefore="true"
          camunda:delegateExpression="${asyncService}"
          camunda:exclusive="true">
      <extensionElements>
        <camunda:inputOutput>
          <camunda:inputParameter name="service.uri">/process/services/helloworld/async</camunda:inputParameter>
          <camunda:inputParameter name="yourName">${variables.getDisplayValue("dv_initiator")}</camunda:inputParameter>
        </camunda:inputOutput>
      </extensionElements>
    </sendTask>
    <receiveTask id="receive_service_response"
          name="Wait for Service 'Hello World'"
          camunda:asyncAfter="true"
          camunda:exclusive="true">
      <extensionElements>
        <camunda:inputOutput>
          <camunda:outputParameter name="greeting">${variables.get("greeting")}</camunda:outputParameter>
        </camunda:inputOutput>
      </extensionElements>
    </receiveTask>
    <userTask id="task_hello_world" name="${variables.get('greeting')}" camunda:assignee="${variables.get('dv_initiator')}" />
    <endEvent id="end" />
    <sequenceFlow id="s1" sourceRef="start" targetRef="call_service" />
    <sequenceFlow id="s2" sourceRef="call_service" targetRef="receive_service_response" />
    <sequenceFlow id="s3" sourceRef="receive_service_response" targetRef="task_hello_world" />
    <sequenceFlow id="s4" sourceRef="task_hello_world" targetRef="end" />
  </process>
  
  <!-- Diagram information -->
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="async_service_process">
      <bpmndi:BPMNEdge id="s4_di" bpmnElement="s4">
        <di:waypoint x="630" y="117" />
        <di:waypoint x="662" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="s3_di" bpmnElement="s3">
        <di:waypoint x="490" y="117" />
        <di:waypoint x="530" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="s2_di" bpmnElement="s2">
        <di:waypoint x="350" y="117" />
        <di:waypoint x="390" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="s1_di" bpmnElement="s1">
        <di:waypoint x="215" y="117" />
        <di:waypoint x="250" y="117" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="start_di" bpmnElement="start">
        <dc:Bounds x="179" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="call_service_di" bpmnElement="call_service">
        <dc:Bounds x="250" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="receive_service_response_di" bpmnElement="receive_service_response">
        <dc:Bounds x="390" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="task_hello_world_di" bpmnElement="task_hello_world">
        <dc:Bounds x="530" y="77" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="end_di" bpmnElement="end">
        <dc:Bounds x="662" y="99" width="36" height="36" />
      </bpmndi:BPMNShape>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Frequently asked questions

In this topic, you will find answers to frequently asked questions. 

Why does an unknown server error occur when a variable is inserted?

If you want to insert a process variable which already exists with different capitalization, an error may occur. The error occurs if the sorting of the database does not take into account capitalization and therefore cannot distinguish between the two variables.

To prevent the error, please use the capitalization already used when inserting a variable.

Where can I find a summary of all actions?

When you switch to the perspective Action summary in the Process administration feature, you get an overview of all ongoing, started, completed and failed actions. You can use the trash icon to remove completed and failed actions from the log manually.

Imprint and legal notices

With the publication of this documentation, all previous documentations become invalid.

The information contained in this documentation has been compiled with the greatest care and checked by our Quality Assurance department in accordance with the general state of the art. Despite this, errors cannot be ruled out entirely. For this reason, the information contained in this documentation does not constitute an obligation, promised feature or guarantee. d.velop AG assumes no liability or warranty on the basis of this documentation. Claims under the German product liability act and tort law shall remain unaffected unless they have been excluded by individual contract.
Statements regarding statutory, legal and tax regulations and their implications are only valid for the Federal Republic of Germany.
d.velop AG reserves the right to replace existing third-party components in its software with functionally adequate components from other manufacturers. In the exercise of its valid release policy, d.velop AG reserves the right to no longer support product features and individual software products with software maintenance and support services. You can find more information about this in the support lifecycle of the d.velop service portal at https://portal.d-velop.de.

The use of texts, images, graphics and their arrangements, including in extracts, is not permitted without the prior consent of d.velop AG.
All hardware and software names used are trade names and/or trademarks of the respective manufacturers/owners who provided them.

Should parts of or individual formulations within this documentation not, no longer or not fully comply with the prevailing legal position, the content or validity of the other parts of the documentation remains unaffected by this fact.
Within the documentation, you can navigate via links to external websites that are not operated by us. These links are either clearly marked by us or can be recognized by a change in the address line of your browser. We are not responsible for the content of these external websites.

Contact
d.velop AG
Schildarpstrasse 6-8
48712 Gescher, Germany

Tel: +49 2542 9307-0
d-velop.de or info@d-velop.de

Represented by the Board of Directors: Christoph Pliete (Chairman), Mario Dönnebrink
Chairman of the Supervisory Board: Dr. Helmut Bäumer
Commercial Register at Coesfeld Local Court, No. HRB 4903
Sales tax identification number: DE 813062165 

If you have any questions about this documentation or the software, please contact us.
Tel: +49 2542 9307-6000
support@d-velop.de
© d.velop AG. All rights reserved.

This document was last revised on 05/04/2021.

Document name: processapp_eng.pdf (build number: 20210504)