To create simple BPMN processes we provide a fluent builder API. With this API you can easily create basicprocesses in a few lines of code. In the generate process fluent api quickstart wedemonstrate how to create a rather complex process with 5 tasks and 2 gateways within less than 50 lines of code.
The fluent builder API is not nearly complete but provides you with the following basic elements:
- process
- start event
- exclusive gateway
- parallel gateway
- script task
- service task
- user task
- signal event definition
- end event
- subprocess
Create a Process With the Fluent Builder API
To create an empty model instance with a new process the method Bpmn.createProcess()
is used. After this,you can add as many tasks and gateways as you like. At the end you must call done()
to return the generatedmodel instance. For example, a simple process with one user task can be created like this:
BpmnModelInstance modelInstance = Bpmn.createProcess()
.startEvent()
.userTask()
.endEvent()
.done();
To add a new element you have to call a function which is named like theelement to add. Additionally you can set attributes of the last createdelement.
For example, let’s set the name of the process and mark it as executable and also give the user task a name.
BpmnModelInstance modelInstance = Bpmn.createProcess()
.name("Example process")
.executable()
.startEvent()
.userTask()
.name("Some work to do")
.endEvent()
.done();
As you can see, a sequential process is really simple and straightforward to model, but often you wantbranches and a parallel execution path, which is also possible with the fluent builder API. Just adda parallel or exclusive gateway and model the first path till an end event or another gateway. After that,call the moveToLastGateway()
method and you return to the last gateway and can model the next path.
BpmnModelInstance modelInstance = Bpmn.createProcess()
.startEvent()
.userTask()
.parallelGateway()
.scriptTask()
.endEvent()
.moveToLastGateway()
.serviceTask()
.endEvent()
.done();
This example models a process with a user task after the start event followed by a parallel gatewaywith two parallel outgoing execution paths, each with a task and an end event.
Normally you want to add conditions on outgoing flows of an exclusive gateway which is also simple withthe fluent builder API. Just use the method condition()
and give it a label and an expression.
BpmnModelInstance modelInstance = Bpmn.createProcess()
.startEvent()
.userTask()
.exclusiveGateway()
.name("What to do next?")
.condition("Call an agent", "#{action = 'call'}")
.scriptTask()
.endEvent()
.moveToLastGateway()
.condition("Create a task", "#{action = 'task'}")
.serviceTask()
.endEvent()
.done();
If you want to use the moveToLastGateway()
method but have multiple incomingsequence flows at your current position, you have to use the genericmoveToNode
method with the id of the gateway. This could for example happenif you add a join gateway to your process. For this purpose and for loops, weadded the connectTo(elementId)
method.
BpmnModelInstance modelInstance = Bpmn.createProcess()
.startEvent()
.userTask()
.parallelGateway("fork")
.serviceTask()
.parallelGateway("join")
.moveToNode("fork")
.userTask()
.connectTo("join")
.moveToNode("fork")
.scriptTask()
.connectTo("join")
.endEvent()
.done()
This example creates a process with three parallel execution paths which alljoin in the second gateway. Notice that the first call of moveToNode
is notnecessary, because at this point the joining gateway only has one incoming sequenceflow, but was used for consistency.
BpmnModelInstance modelInstance = Bpmn.createProcess()
.startEvent()
.userTask()
.id("question")
.exclusiveGateway()
.name("Everything fine?")
.condition("yes", "#{fine}")
.serviceTask()
.userTask()
.endEvent()
.moveToLastGateway()
.condition("no", "#{!fine}")
.userTask()
.connectTo("question")
.done()
This example creates a parallel gateway with a feedback loop in the second execution path.
To create an embedded subprocess with the fluent builder API, you can directly add it to yourprocess building or you can detach it and create flow elements of the subprocess later on.
// Directly define the subprocess
BpmnModelInstance modelInstance = Bpmn.createProcess()
.startEvent()
.subProcess()
.camundaAsync()
.embeddedSubProcess()
.startEvent()
.userTask()
.endEvent()
.subProcessDone()
.serviceTask()
.endEvent()
.done();
// Detach the subprocess building
modelInstance = Bpmn.createProcess()
.startEvent()
.subProcess("subProcess")
.serviceTask()
.endEvent()
.done();
SubProcess subProcess = (SubProcess) modelInstance.getModelElementById("subProcess");
subProcess.builder()
.camundaAsync()
.embeddedSubProcess()
.startEvent()
.userTask()
.endEvent();
The example below shows how to create a throwing signal event definition and define the payload that this signal will contain. By using the camundaIn
methods, it is possible to define which process variables will be included in the signal payload, define an expression that will be resolved in the signal-catching process instances, or declare that all of the process variables in the signal-throwing process instance should be passed. It is also possible to define a business key that will be assigned to the signal-catching process instances.
BpmnModelInstance modelInstance = Bpmn.createProcess()
.startEvent()
.intermediateThrowEvent("throw")
.signalEventDefinition("signal")
.camundaInSourceTarget("source", "target1")
.camundaInSourceExpressionTarget("${'sourceExpression'}", "target2")
.camundaInAllVariables("all", true)
.camundaInBusinessKey("aBusinessKey")
.throwEventDefinitionDone()
.endEvent()
.done();
Extend a Process With the Fluent Builder API
With the fluent builder API you can not only create processes, you can also extend existing processes.
For example, imagine a process containing a parallel gateway with the id gateway
. You now want toadd another execution path to it for a new service task which has to be executed every time.
BpmnModelInstance modelInstance = Bpmn.readModelFromFile(new File("PATH/TO/MODEL.bpmn"));
ParallelGateway gateway = (ParallelGateway) modelInstance.getModelElementById("gateway");
gateway.builder()
.serviceTask()
.name("New task")
.endEvent();
Another use case is to insert new tasks between existing elements. Imagine a processcontaining a user task with the id task1
which is followed by a service task. And nowyou want to add a script task and a user task between these two.
BpmnModelInstance modelInstance = Bpmn.readModelFromFile(new File("PATH/TO/MODEL.bpmn"));
UserTask userTask = (UserTask) modelInstance.getModelElementById("task1");
SequenceFlow outgoingSequenceFlow = userTask.getOutgoing().iterator().next();
FlowNode serviceTask = outgoingSequenceFlow.getTarget();
userTask.getOutgoing().remove(outgoingSequenceFlow);
userTask.builder()
.scriptTask()
.userTask()
.connectTo(serviceTask.getId());
Generation of Diagram Interchange
To render the process, BPMN diagram elements are necessary. The fluent builder generatesBPMN Shapes and BPMN Edges and places them automatically for flow nodes and sequence flows.
final BpmnModelInstance myProcess = Bpmn.createExecutableProcess("process-payments")
.startEvent()
.serviceTask()
.name("Process Payment")
.endEvent()
.done();
System.out.println(Bpmn.convertToString(myProcess));
This example creates a BPMN containing both semantic elements (e.g., service task etc.) and diagram elements:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<definitions xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="definitions_dfb1f18e-6034-448e-abae-0eb2f41469da" targetNamespace="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL">
<!-- Generated BPMN Semantic Elements -->
<process id="process-payments" isExecutable="true">
<startEvent id="startEvent_2b0abd37-75a9-47dd-9838-63f1390d7515">
<outgoing>sequenceFlow_b1eec5b5-889d-4e75-854d-59768fbdc8a2</outgoing>
</startEvent>
<serviceTask id="serviceTask_f4c2413f-5b26-49e8-b71c-2603e469ce09" name="Process Payment">
<incoming>sequenceFlow_b1eec5b5-889d-4e75-854d-59768fbdc8a2</incoming>
<outgoing>sequenceFlow_5839394a-c0c2-4a5b-aa81-9412f169cc35</outgoing>
</serviceTask>
<sequenceFlow id="sequenceFlow_b1eec5b5-889d-4e75-854d-59768fbdc8a2" sourceRef="startEvent_2b0abd37-75a9-47dd-9838-63f1390d7515" targetRef="serviceTask_f4c2413f-5b26-49e8-b71c-2603e469ce09"/>
<endEvent id="endEvent_8087f927-a53b-4126-95fc-c057736f3b73">
<incoming>sequenceFlow_5839394a-c0c2-4a5b-aa81-9412f169cc35</incoming>
</endEvent>
<sequenceFlow id="sequenceFlow_5839394a-c0c2-4a5b-aa81-9412f169cc35" sourceRef="serviceTask_f4c2413f-5b26-49e8-b71c-2603e469ce09" targetRef="endEvent_8087f927-a53b-4126-95fc-c057736f3b73"/>
</process>
<!-- Generated Diagram Elements -->
<bpmndi:BPMNDiagram id="BPMNDiagram_5b66dfb7-097b-4610-9681-43abb3ff97da">
<bpmndi:BPMNPlane bpmnElement="process-payments" id="BPMNPlane_ad88b4cf-9d7a-4b86-8386-f8db23ff388d">
<bpmndi:BPMNShape bpmnElement="startEvent_2b0abd37-75a9-47dd-9838-63f1390d7515" id="BPMNShape_d6c4e3c5-150c-43f7-adf8-1d388f466a69">
<dc:Bounds height="36.0" width="36.0" x="100.0" y="100.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="serviceTask_f4c2413f-5b26-49e8-b71c-2603e469ce09" id="BPMNShape_51006773-13df-4327-a4cf-a5952c39e86a">
<dc:Bounds height="80.0" width="100.0" x="186.0" y="78.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_b1eec5b5-889d-4e75-854d-59768fbdc8a2" id="BPMNEdge_fb360594-8863-4d5d-b515-49e02a88d55d">
<di:waypoint x="136.0" y="118.0"/>
<di:waypoint x="186.0" y="118.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape bpmnElement="endEvent_8087f927-a53b-4126-95fc-c057736f3b73" id="BPMNShape_23930820-5507-45a0-8630-b5e45ee8dd4d">
<dc:Bounds height="36.0" width="36.0" x="336.0" y="100.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sequenceFlow_5839394a-c0c2-4a5b-aa81-9412f169cc35" id="BPMNEdge_07ed502e-069f-42a0-bd1b-fed0d68efbda">
<di:waypoint x="286.0" y="118.0"/>
<di:waypoint x="336.0" y="118.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
The default behavior is that each newly added flow element will be placed next to the previous flow element.
When flow elements are added to an embedded subprocess, then the subprocess is resized when the subprocess border is reached. Therefore,it is recommended to first add all new elements to the subprocess and to then create the following elements. Otherwise it could lead tooverlapping elements in the diagram.
Branches of gateways are placed one below the other. Auto layout is not provided, therefore the elements of different branches may overlap.
原文: https://docs.camunda.org/manual/7.9/user-guide/model-api/bpmn-model-api/fluent-builder-api/