Open Documentation Menu

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="" exporter="d.velop process modeler">
  <process id="sync_service_process" name="Sync Service Process" isExecutable="true">
    <startEvent id="start" />
    <userTask id="task_hello_world" name="Hello World" camunda:candidateUsers="${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="service:/process/services/helloworld/sync:name" value="Hello World" />
      <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:candidateUsers="${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>

In order for the BPMN diagram to be displayed correctly in the modeling tool as well as the user interface, diagram information has been added. 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="" exporter="d.velop process modeler">
  <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="service:/process/services/helloworld/sync:name" value="Hello World" /> 
        <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:candidateUsers="${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="" exporter="d.velop process modeler">
  <process id="async_service_process" name="Async Service Process" isExecutable="true">
    <startEvent id="start" />
    <userTask id="task_hello_world" name="Hello World" camunda:candidateUsers="${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:inputParameter name="service.callbackBase">/</camunda:inputParameter>
          </camunda:inputOutput>
    </extensionElements>
  </sendTask>
  ...
</process>

Explanation of the parameters:

  • service.uri: This parameter is mandatory and therefore must always be inserted. The parameter 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. the value 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.

Modifying the response URIs

You can change the origin of the URIs passed to the service for the response. You have the following two options for this.

Specifying the Origin on the SendTask of a concrete service

...
<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.callbackBase">/</camunda:inputParameter>
                ...
          </camunda:inputOutput>
    </extensionElements>
  </sendTask>
  ...
</process>

Add another camunda:inputParameter named service.callbackBase to the SendTask. This parameter is valid for this specific service call.

Specifying the Origin for the entire process

Enter the BPMN elements extensionElements and camunda:properties into the process definition.

...
<process id="async_service_process" name="Async Service Process" isExecutable="true">
  <extensionElements>
    <camunda:properties>
          ...
      <camunda:property name="service:/process/services/helloworld/async:callbackBase" value="/" />
      <!-- alternative <camunda:property name="service:*:callbackBase" value="/" /> -->
      ...
    </camunda:properties>
  </extensionElements>
  ...
</process>

Create a camunda:property element named service:<service>:callbackBase. The <service> placeholder represents the URI of the service, or * for all services.

The specified Origin must match the format https://domain[:port] in both cases. Alternatively, the specification of / represents a relative URI.

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, if not already done in previous steps. 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="service:/process/services/helloworld/async:name" value="Hello World" /> 
      <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:candidateUsers="${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>

In order for the BPMN diagram to be displayed correctly in the modeling tool as well as the user interface, diagram information has been added. 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="" exporter="d.velop process modeler">
  <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="service:/process/services/helloworld/async:name" value="Hello World" />  
        <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:candidateUsers="${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>