Build Your Business App With BPMN 2.0
This tutorial demonstrates how to build a business application with the Business Process Modelling Notation (BPMN 2.0), a model-driven approach.
Join the DZone community and get the full member experience.
Join For FreeIn this short tutorial, I will show how to build a business application with the Business Process Modelling Notation – BPMN. This approach differs from the usual data-centric approach as we focus on process management instead of data processing.
Data Processing vs. Process Management
When we follow the classic approach of building a Data-Centric Business Application, we usually first design a data schema. The data schema defines what kind of data can be managed. The application allows us to create new data sets, edit existing data, and, of course, search for data.
In a Process-Centric Business Application, we instead first try to answer the question of how data should be processed to give each actor the best access to information to reach a specific business goal. This kind of question becomes more and more important in today’s rapidly evolving business landscape. BPMN offers the perfect approach to model a workflow with its business goals from the beginning to the end. BPMN models can be created with various tools like the Open Source BPMN designer Open-BPMN, for example.
The big advantage of BPMN is that it does not only give all stakeholders a clear understanding about the process, but a BPMN 2.0 Model can also be executed by a suitable process engine. This “low-code” or “model-driven” approach leads to a much more flexible way to implement business applications. Of course, data still plays an important role, and workflow engines allow us to manage business data in various ways. So let’s see how this works.
Start With a Business Process
First of all, we have to think about the business process behind our business app. Before we think about data, we should focus on questions like:
- Why do we need this kind of information?
- Who is responsible to create or update data?
- Which steps are necessary to process data correctly?
- What do we expect to happen next?
As mentioned before, a business process defines the way to achieve a concrete business goal. In a BPMN model, we can describe this way from its beginning to the end. See the following example of a simple "Proposal Creation Process":
The BPMN model defines a Start- (green) and End- (red) event to mark the beginning and end of the process. An Activity Element (blue boxes in this diagram) defines a single task in the business process. This can also be a milestone to be reached. An event (blue circle) defines the transition into a new task or status. An event can be triggered externally (e.g., "Order received from customer") or by an actor (e.g., "Proposal created and submitted for review"). In this way, we get a sequence flow – the workflow.
Business Rules
In addition to the sequence flow, we can define business rules to implement additional business logic. For example, we can define that a Review in this example process is only needed for Proposals with a bid amount over 1,000,00 EUR. For this, we can add an Exclusive Gateway with conditional flows to the diagram:
In this example, the transition (Sequence Flow) between "Gateway-1" and the "Review Task" now contains a condition; e.g.:
workitem.getItemValueDouble('amount')>=1000.0
A BPMN engine can evaluate these kinds of conditions by different script languages based on the data provided in the workflow. The data can either be stored directly in the process instance, or defined by a reference to an external data source. There are a number of more elements defined in the BPMN 2.0 standard that allow the modeling even of much more complex business processes.
Run Your Business Process
Now let’s see how we can start and control such a BPMN process in an application by using a BPMN engine. There are various BPMN engines available and a lot of them are open source. See the list of awesome-workflow-engines maintained by @meirwah on GitHub.
In the following, I use the Imixs-Workflow engine, which supports BPMN 2.0 and provides a Docker container that allows us to start out of the box without the need to write any code. With the Imixs-Microservice we can start the BPMN Workflow engine in a container. Just create a local docker-compose.yaml
file with the following content:
services:
imixs-db:
image: postgres:13.11
environment:
POSTGRES_PASSWORD: adminadmin
POSTGRES_DB: workflow-db
imixs-app:
image: imixs/imixs-microservice:latest
environment:
TZ: "CET"
LANG: "en_US.UTF-8"
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "adminadmin"
POSTGRES_CONNECTION: "jdbc:postgresql://imixs-db/workflow-db"
ports:
- "8080:8080"
Start the service with:
$ docker compose up
The service starts with a short welcome page at http://localhost:8080
and provides a REST interface at http://localhost:8080/api/openapi-ui/index.html
. This REST API user interface allows us to test various methods to start a workflow or to process existing ones.
Upload Your Model
First, we need to upload our model. For this, we can use the curl
command and post our BPMN file to the REST Service endpoint:
$ curl --user admin:adminadmin --request POST \
-Tmy-model.bpmn http://localhost:8080/api/model/bpmn
Or we can use the REST API UI to post the model at the resource /api/model/bpmn/
.
You can download the test model from GitHub or you create a new file my-model.bpmn
with the following content:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- origin at X=0.0 Y=0.0 --><bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" 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" xmlns:ext="http://org.eclipse.bpmn2/ext" xmlns:imixs="http://www.imixs.org/bpmn2" xmlns:open-bpmn="http://open-bpmn.org/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exporter="org.eclipse.bpmn2.modeler.core" exporterVersion="1.5.2.SNAPSHOT-v20200526-1743-B1" id="Definitions_1" targetNamespace="http://www.imixs.org/bpmn2">
<bpmn2:extensionElements>
<imixs:item name="txtworkflowmodelversion" type="xs:string">
<imixs:value><![CDATA[proposal-en-1.0]]></imixs:value>
</imixs:item>
<imixs:item name="txtfieldmapping" type="xs:string">
<imixs:value><![CDATA[Team|team]]></imixs:value>
<imixs:value><![CDATA[Creator|$creator]]></imixs:value>
<imixs:value><![CDATA[CurrentEditor|$editor]]></imixs:value>
</imixs:item>
<imixs:item name="txtplugins" type="xs:string">
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.OwnerPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.HistoryPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ResultPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.LogPlugin]]></imixs:value>
<imixs:value><![CDATA[org.imixs.workflow.engine.plugins.ApplicationPlugin]]></imixs:value>
</imixs:item>
<open-bpmn:auto-align>true</open-bpmn:auto-align>
</bpmn2:extensionElements>
<bpmn2:collaboration id="Collaboration_1" name="Collaboration 1">
<bpmn2:participant id="Participant_1" name="Proposal" processRef="Process_1">
<bpmn2:documentation id="documentation_0zO0SQ"><![CDATA[Proposal Creation and Review Process]]></bpmn2:documentation>
</bpmn2:participant>
<bpmn2:participant id="Participant_2" name="Ticket Pool" processRef="ticket"/>
<bpmn2:association id="Association_2" sourceRef="CallConversation_1" targetRef="IntermediateCatchEvent_3"/>
<bpmn2:callConversation id="CallConversation_1" name="Stock Service"/>
</bpmn2:collaboration>
<bpmn2:process id="ticket" isExecutable="false" name="Ticket">
<bpmn2:documentation id="documentation_hijN6w"/>
</bpmn2:process>
<bpmn2:process definitionalCollaborationRef="Collaboration_1" id="Process_1" isExecutable="false" name="Proposal">
<bpmn2:laneSet id="LaneSet_4" name="Lane Set 4">
<bpmn2:lane id="Lane_2" name="Team">
<bpmn2:flowNodeRef>Task_2</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>IntermediateCatchEvent_1</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>StartEvent_1</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>Task_1</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>IntermediateCatchEvent_7</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>Task_4</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>EndEvent_1</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>IntermediateCatchEvent_8</bpmn2:flowNodeRef>
<bpmn2:documentation id="documentation_jDXHNg"/>
<bpmn2:flowNodeRef>TextAnnotation_2</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_R0B00Q</bpmn2:flowNodeRef>
<bpmn2:flowNodeRef>gateway_7zm0sw</bpmn2:flowNodeRef>
</bpmn2:lane>
</bpmn2:laneSet>
<bpmn2:task id="Task_2" imixs:processid="1100" name="Review">
<bpmn2:extensionElements>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>subject</itemvalue> ]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:boolean">
<imixs:value>true</imixs:value>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string"/>
<imixs:item name="keyaddwritefields" type="xs:string"/>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_gfOqDA"/>
<bpmn2:outgoing>sequenceFlow_fCuqCw</bpmn2:outgoing>
<bpmn2:incoming>sequenceFlow_7jbDFQ</bpmn2:incoming>
</bpmn2:task>
<bpmn2:endEvent id="EndEvent_1" name="End">
<bpmn2:incoming>SequenceFlow_12</bpmn2:incoming>
<bpmn2:documentation id="documentation_XhiRag"/>
</bpmn2:endEvent>
<bpmn2:intermediateCatchEvent id="IntermediateCatchEvent_1" imixs:activityid="10" name="Submit">
<bpmn2:extensionElements>
<imixs:item name="rtfresultlog" type="CDATA">
<imixs:value><![CDATA[Order submitted by <itemvalue>$Editor</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="txtactivityresult" type="CDATA">
<imixs:value><![CDATA[<item name="batch.event.id">20</item>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:boolean">
<imixs:value>false</imixs:value>
</imixs:item>
<imixs:item name="keyownershipfields" type="xs:string"/>
<imixs:item name="keyaddreadfields" type="xs:string"/>
<imixs:item name="keyaddwritefields" type="xs:string"/>
</bpmn2:extensionElements>
<bpmn2:documentation id="Documentation_12"><b>Submit</b> a new ticket</bpmn2:documentation>
<bpmn2:incoming>SequenceFlow_11</bpmn2:incoming>
<bpmn2:outgoing>SequenceFlow_3</bpmn2:outgoing>
<bpmn2:outputSet id="OutputSet_1" name="Output Set 1"/>
</bpmn2:intermediateCatchEvent>
<bpmn2:sequenceFlow id="SequenceFlow_3" sourceRef="IntermediateCatchEvent_1" targetRef="gateway_7zm0sw">
<bpmn2:documentation id="documentation_Go9yMg"/>
</bpmn2:sequenceFlow>
<bpmn2:task id="Task_4" imixs:processid="1900" name="Completed">
<bpmn2:extensionElements>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>subject</itemvalue> ]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:boolean">
<imixs:value>true</imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:outgoing>SequenceFlow_12</bpmn2:outgoing>
<bpmn2:documentation id="documentation_kIH5yg"/>
<bpmn2:incoming>sequenceFlow_BYx0Eg</bpmn2:incoming>
<bpmn2:incoming>sequenceFlow_O00HWA</bpmn2:incoming>
</bpmn2:task>
<bpmn2:sequenceFlow id="SequenceFlow_12" sourceRef="Task_4" targetRef="EndEvent_1">
<bpmn2:documentation id="documentation_yNPUlA"/>
</bpmn2:sequenceFlow>
<bpmn2:startEvent id="StartEvent_1" name="Start">
<bpmn2:outgoing>SequenceFlow_1</bpmn2:outgoing>
<bpmn2:documentation id="documentation_igq0Jw"/>
</bpmn2:startEvent>
<bpmn2:sequenceFlow id="SequenceFlow_1" sourceRef="StartEvent_1" targetRef="Task_1">
<bpmn2:documentation id="documentation_JM9HUQ"/>
</bpmn2:sequenceFlow>
<bpmn2:task id="Task_1" imixs:processid="1000" name="Create Draft">
<bpmn2:extensionElements>
<imixs:item name="txtworkflowsummary" type="xs:string">
<imixs:value><![CDATA[<itemvalue>subject</itemvalue> ]]></imixs:value>
</imixs:item>
<imixs:item name="txtworkflowabstract" type="CDATA">
<imixs:value><![CDATA[Create a new Ticket workflow]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="Documentation_1">Create a new ticket</bpmn2:documentation>
<bpmn2:incoming>SequenceFlow_1</bpmn2:incoming>
<bpmn2:outgoing>SequenceFlow_11</bpmn2:outgoing>
<bpmn2:incoming>sequenceFlow_jspJig</bpmn2:incoming>
</bpmn2:task>
<bpmn2:sequenceFlow id="SequenceFlow_11" sourceRef="Task_1" targetRef="IntermediateCatchEvent_1">
<bpmn2:documentation id="documentation_O8sN9Q"/>
</bpmn2:sequenceFlow>
<bpmn2:intermediateCatchEvent id="IntermediateCatchEvent_7" imixs:activityid="10" name="Approve">
<bpmn2:extensionElements>
<imixs:item name="rtfresultlog" type="CDATA">
<imixs:value><![CDATA[Oder placed, payment initialized]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:boolean">
<imixs:value>false</imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string"/>
<imixs:item name="keypublicresult" type="xs:string">
<imixs:value><![CDATA[1]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_7H9ztw"/>
<bpmn2:incoming>sequenceFlow_Wn3NGw</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_BYx0Eg</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:intermediateCatchEvent id="IntermediateCatchEvent_8" imixs:activityid="20" name="Reject">
<bpmn2:extensionElements>
<imixs:item name="rtfresultlog" type="CDATA">
<imixs:value><![CDATA[ticket solved by <itemvalue>namcurrentEditor</itemvalue>]]></imixs:value>
</imixs:item>
<imixs:item name="keyupdateacl" type="xs:boolean">
<imixs:value>false</imixs:value>
</imixs:item>
<imixs:item name="keyaddwritefields" type="xs:string"/>
<imixs:item name="keypublicresult" type="xs:string">
<imixs:value><![CDATA[1]]></imixs:value>
</imixs:item>
</bpmn2:extensionElements>
<bpmn2:documentation id="documentation_gk0TWg"/>
<bpmn2:incoming>sequenceFlow_GNxY5A</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_jspJig</bpmn2:outgoing>
</bpmn2:intermediateCatchEvent>
<bpmn2:textAnnotation id="TextAnnotation_2" textFormat="">
<bpmn2:text><![CDATA[Proposal Creation and Review Process with conditional events.]]></bpmn2:text>
<bpmn2:documentation id="documentation_XzWNOw"/>
</bpmn2:textAnnotation>
<bpmn2:eventBasedGateway gatewayDirection="Diverging" id="gateway_R0B00Q" name="Gateway-2">
<bpmn2:documentation id="documentation_rJq1dg"/>
<bpmn2:incoming>sequenceFlow_fCuqCw</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_GNxY5A</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_Wn3NGw</bpmn2:outgoing>
</bpmn2:eventBasedGateway>
<bpmn2:sequenceFlow id="sequenceFlow_fCuqCw" sourceRef="Task_2" targetRef="gateway_R0B00Q">
<bpmn2:documentation id="documentation_GihGJA"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_GNxY5A" sourceRef="gateway_R0B00Q" targetRef="IntermediateCatchEvent_8">
<bpmn2:documentation id="documentation_y73G7A"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_jspJig" sourceRef="IntermediateCatchEvent_8" targetRef="Task_1">
<bpmn2:documentation id="documentation_AG6lqA"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_Wn3NGw" sourceRef="gateway_R0B00Q" targetRef="IntermediateCatchEvent_7">
<bpmn2:documentation id="documentation_DgUkAA"/>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_BYx0Eg" sourceRef="IntermediateCatchEvent_7" targetRef="Task_4">
<bpmn2:documentation id="documentation_Hdvb8g"/>
</bpmn2:sequenceFlow>
<bpmn2:exclusiveGateway default="sequenceFlow_O00HWA" gatewayDirection="Diverging" id="gateway_7zm0sw" name="Gateway-1">
<bpmn2:documentation id="documentation_1V8eMg"/>
<bpmn2:incoming>SequenceFlow_3</bpmn2:incoming>
<bpmn2:outgoing>sequenceFlow_7jbDFQ</bpmn2:outgoing>
<bpmn2:outgoing>sequenceFlow_O00HWA</bpmn2:outgoing>
</bpmn2:exclusiveGateway>
<bpmn2:sequenceFlow id="sequenceFlow_7jbDFQ" name=">=1.000" sourceRef="gateway_7zm0sw" targetRef="Task_2">
<bpmn2:documentation id="documentation_L6UXlA"/>
<bpmn2:conditionExpression id="formalExpression_SDqySQ" xsi:type="bpmn2:tFormalExpression"><![CDATA[workitem.getItemValueDouble('amount')>=1000.0]]></bpmn2:conditionExpression>
</bpmn2:sequenceFlow>
<bpmn2:sequenceFlow id="sequenceFlow_O00HWA" name="<1.000" sourceRef="gateway_7zm0sw" targetRef="Task_4">
<bpmn2:documentation id="documentation_3uCjHQ"/>
</bpmn2:sequenceFlow>
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1" name="Default Process Diagram">
<bpmndi:BPMNPlane bpmnElement="Collaboration_1" id="BPMNPlane_1">
<bpmndi:BPMNShape bpmnElement="Participant_1" id="BPMNShape_Participant_1" isHorizontal="true">
<dc:Bounds height="330.0" width="1210.0" x="100.0" y="150.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Lane_2" id="BPMNShape_Lane_2" isHorizontal="true">
<dc:Bounds height="330.0" width="1180.0" x="130.0" y="150.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="StartEvent_1" id="BPMNShape_1">
<dc:Bounds height="36.0" width="36.0" x="207.0" y="317.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_1" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="20.0" width="100.0" x="175.5" y="356.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="EndEvent_1" id="BPMNShape_2">
<dc:Bounds height="36.0" width="36.0" x="1237.0" y="317.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_2" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="20.0" width="100.0" x="1208.0" y="356.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Task_1" id="BPMNShape_Task_1">
<dc:Bounds height="50.0" width="110.0" x="300.0" y="310.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Task_2" id="BPMNShape_Task_2">
<dc:Bounds height="50.0" width="110.0" x="680.0" y="310.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="Task_4" id="BPMNShape_Task_4">
<dc:Bounds height="50.0" width="110.0" x="1070.0" y="310.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="IntermediateCatchEvent_1" id="BPMNShape_IntermediateCatchEvent_1">
<dc:Bounds height="36.0" width="36.0" x="457.0" y="317.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_8" labelStyle="BPMNLabelStyle_1">
<dc:Bounds height="20.0" width="100.0" x="422.0" y="358.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="CallConversation_1" id="BPMNShape_CallConversation_1">
<dc:Bounds height="50.0" width="58.0" x="679.0" y="560.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_38">
<dc:Bounds height="14.0" width="74.0" x="671.0" y="610.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="IntermediateCatchEvent_7" id="BPMNShape_IntermediateCatchEvent_7">
<dc:Bounds height="36.0" width="36.0" x="967.0" y="317.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_43">
<dc:Bounds height="20.0" width="100.0" x="938.0" y="356.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="IntermediateCatchEvent_8" id="BPMNShape_IntermediateCatchEvent_8">
<dc:Bounds height="36.0" width="36.0" x="867.0" y="397.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_44">
<dc:Bounds height="20.0" width="100.0" x="834.5" y="436.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="TextAnnotation_2" id="BPMNShape_TextAnnotation_2">
<dc:Bounds height="89.0" width="176.0" x="183.0" y="166.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="SequenceFlow_1" id="BPMNEdge_SequenceFlow_1" sourceElement="BPMNShape_1" targetElement="BPMNShape_Task_1">
<bpmndi:BPMNLabel id="BPMNLabel_3" labelStyle="BPMNLabelStyle_1"/>
<di:waypoint x="243.0" y="335.0"/>
<di:waypoint x="300.0" y="335.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="SequenceFlow_3" id="BPMNEdge_SequenceFlow_3" sourceElement="BPMNShape_IntermediateCatchEvent_1" targetElement="BPMNShape_D6F8wQ">
<bpmndi:BPMNLabel id="BPMNLabel_12" labelStyle="BPMNLabelStyle_1"/>
<di:waypoint x="493.0" y="335.0"/>
<di:waypoint x="540.0" y="335.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="SequenceFlow_12" id="BPMNEdge_SequenceFlow_12" sourceElement="BPMNShape_Task_4" targetElement="BPMNShape_2">
<bpmndi:BPMNLabel id="BPMNLabel_26" labelStyle="BPMNLabelStyle_1"/>
<di:waypoint x="1180.0" y="335.0"/>
<di:waypoint x="1237.0" y="335.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="SequenceFlow_11" id="BPMNEdge_SequenceFlow_11" sourceElement="BPMNShape_Task_1" targetElement="BPMNShape_IntermediateCatchEvent_1">
<bpmndi:BPMNLabel id="BPMNLabel_25"/>
<di:waypoint x="410.0" y="335.0"/>
<di:waypoint x="457.0" y="335.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="Association_2" id="BPMNEdge_Association_2" sourceElement="BPMNShape_CallConversation_1" targetElement="BPMNShape_IntermediateCatchEvent_3">
<di:waypoint x="708.0" xsi:type="dc:Point" y="560.0"/>
<di:waypoint x="708.0" xsi:type="dc:Point" y="458.0"/>
<di:waypoint x="708.0" xsi:type="dc:Point" y="356.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_39"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="gateway_R0B00Q" id="BPMNShape_LOkyeA">
<dc:Bounds height="50.0" width="50.0" x="860.0" y="310.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_9Q0Elg">
<dc:Bounds height="20.0" width="100.0" x="834.0" y="366.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_fCuqCw" id="BPMNEdge_Og8YJw" sourceElement="BPMNShape_Task_2" targetElement="BPMNShape_LOkyeA">
<di:waypoint x="790.0" y="335.0"/>
<di:waypoint x="860.0" y="335.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_GNxY5A" id="BPMNEdge_dksumA" sourceElement="BPMNShape_LOkyeA" targetElement="BPMNShape_IntermediateCatchEvent_8">
<di:waypoint x="885.0" y="360.0"/>
<di:waypoint x="885.0" y="397.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_jspJig" id="BPMNEdge_9kE0mA" sourceElement="BPMNShape_IntermediateCatchEvent_8" targetElement="BPMNShape_Task_1">
<di:waypoint x="867.0" y="415.0"/>
<di:waypoint x="355.0" y="415.0"/>
<di:waypoint x="355.0" y="360.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_Wn3NGw" id="BPMNEdge_MDnJhQ" sourceElement="BPMNShape_LOkyeA" targetElement="BPMNShape_IntermediateCatchEvent_7">
<di:waypoint x="910.0" y="335.0"/>
<di:waypoint x="967.0" y="335.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_BYx0Eg" id="BPMNEdge_EV7fFQ" sourceElement="BPMNShape_IntermediateCatchEvent_7" targetElement="BPMNShape_Task_4">
<di:waypoint x="1003.0" y="335.0"/>
<di:waypoint x="1070.0" y="335.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="gateway_7zm0sw" id="BPMNShape_D6F8wQ">
<dc:Bounds height="50.0" width="50.0" x="540.0" y="310.0"/>
<bpmndi:BPMNLabel id="BPMNLabel_KzYbZw">
<dc:Bounds height="20.0" width="100.0" x="515.0" y="363.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_7jbDFQ" id="BPMNEdge_r6zgwg" sourceElement="BPMNShape_D6F8wQ" targetElement="BPMNShape_Task_2">
<di:waypoint x="590.0" y="335.0"/>
<di:waypoint x="680.0" y="335.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_O00HWA" id="BPMNEdge_spt5Tg" sourceElement="BPMNShape_D6F8wQ" targetElement="BPMNShape_Task_4">
<di:waypoint x="565.0" y="310.0"/>
<di:waypoint x="565.0" y="225.0"/>
<di:waypoint x="1124.0" y="225.0"/>
<di:waypoint x="1124.0" y="310.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
<bpmndi:BPMNLabelStyle id="BPMNLabelStyle_1">
<dc:Font name="arial" size="9.0"/>
</bpmndi:BPMNLabelStyle>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>
The status of all available models can be verified at the REST API endpoint, http://localhost:8080/api/model
.
Note: I use the user ID admin
with the password adminadmin
here. More users with different roles are defined by this service. Find the details on the GitHub repo linked earlier.
Start a New Process Instance
Now that the service is up and running, we can start our first process instance. For this, we just need to post an XML document containing the model information and our business data. We can use the following REST API Endpoint to post a new process instance: POST: /api/workflow/workitem
.
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<item name="$modelversion"><value xsi:type="xs:string">proposal-en-1.0</value></item>
<item name="$taskid"><value xsi:type="xs:int">1000</value></item>
<item name="$eventid"><value xsi:type="xs:int">10</value></item>
<item name="subject">
<value xsi:type="xs:string">My first propsal...</value>
</item>
<item name="amount">
<value xsi:type="xs:double">500.0</value>
</item>
</document>
Again, you can post the data directly with the REST API UI. In this example, I define the modelversion
, the initial task and the event to be processed, as well as some custom business data (subject and amount).
The workflow engine automatically executes the data according to our uploaded BPMN model and returns a result object. To verify the result we can check the tasklist
with all process instances created by the user admin
at http://localhost:8080/api/workflow/tasklist/creator/admin
.
As you can see, the workflow engine has processed our data and applied the status Completed
to our new workflow instance. This was because the amount was below 1.000,00. To test our business logic we can now change the amount to a value greater than 1.000,00 which will start another new process instance in the status Review
according to our business rules.
We can now easily change the process logic and add new tasks or business rules. All we have to do is to upload the new version of the BPMN model. No redeployment of the application is needed.
To update the data of an existing process instance we can post the data together with the $uniqueid
and the corresponding event from our model:
<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<item name="$uniqueid"><value xsi:type="xs:string">8333c61c-b973-4591-aabf-ec92bd59d74b</value></item>
<item name="$eventid"><value xsi:type="xs:int">10</value></item>
<item name="address">
<value xsi:type="xs:string">Baker Street 221b.</value>
</item>
</document>
The field $uniqueid
is returned by the first creation of a new workflow instance and is a reference for further processing steps. In this example, I only provide the reference ID, an Event ID, and some new data. The Workflow engine will verify the request and the event according to the assigned model. This ensures that the data is always processed according to our business process! We can also use the $uniqueID
to fetch the data from the workflow engine – e.g., to display the data in a web interface.
How To Integrate BPMN Into Your App
In this tutorial, I have deliberately omitted the design of a web interface because I wanted to focus on the business logic. When using a REST API – as in this example – the workflow engine can be integrated into an application easily by using different frontend technologies. In addition, there are often other ways to connect a BPMN engine to your own application depending on the framework used by the engine. For example, a lot of open-source engines are based on Java and can be integrated by common build tools like Maven or Gradle.
For example, you can integrate the Imixs Workflow engine into a Jakarta EE app with the following dependencies:
...
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-engine</artifactId>
<version>${org.imixs.workflow.version}</version>
</dependency>
<dependency>
<groupId>org.imixs.workflow</groupId>
<artifactId>imixs-workflow-index-lucene</artifactId>
<version>${org.imixs.workflow.version}</version>
</dependency>
...
Call the engine within your code using the CDI Framework like this:
@Inject
private org.imixs.workflow.engine.WorkflowService workflowService;
ItemCollection workitem=new ItemCollection().model("proposal-en-1.0").task(1000).event(10);
// assign some business data...
workitem.setItemValue("amount",500.0);
// process the workitem
workitem = workflowService.processWorkItem(workitem);
This code example is equal to the REST API call in the example above.
Data Integration
As mentioned before, another aspect is the way you handle your business data. In my example code, I embedded the business data directly into the workflow instance, so no external database was needed.
But of course, in some scenarios, it may be useful to just store a reference to an external dataset and hold the business data in a separate database.
Or you may reference the workflow instance from your data processing application by extending the data schema.
In the last two scenarios, we also need to provide a data service to be able to process the previously mentioned business logic in the process engine. All modern BPMN engines provide interfaces to connect a data source with the process logic.
Conclusion
In summary, incorporating BPMN 2.0 into your business application offers a structured and efficient way to handle your business processes. The ability to visually process models not only simplifies the design and management of complex workflows but also enhances collaboration across technical and non-technical teams. By using tools like Open-BPMN or Imixs-Workflow, you can easily implement BPMN 2.0 standards, ensuring that your business applications are both scalable and adaptable. Embracing BPMN 2.0 can lead to more organized, transparent, and effective business operations, setting the stage for greater success and growth.
Published at DZone with permission of Ralph Soika. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments