We recently released the 5.12 version of Activiti and it’s packed with a lot of new features and improvements. As of the 5.11 version, it’s possible to build BPMN 2.0 processes using a POJO-model. In the latest release, we embrace that POJO-model even more and use it in the core of Activiti as a means of retrieving and deploying process-definitions (on top of the existing deployment formats) using the API.
Combined with other features of Activiti this allows us to build a process, deploy it, start it, test it and retrieve the process definition diagram in under 100 lines of code. By leveraging the new activiti-bpmn-autolayout module, the process elements can be automatically layout, getting the graphical information (BPMN-DI) for free.
I started off with an Activiti unit-test template, which uses a default Activiti-engine running on an in-memory H2 database. The code is written as a simple unit-test, using the built-in JUnit 4 support to have a fully initialized engine and API ready to use when the test starts to run. Full version of the code below can be found on Github.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
@Test
public
void
testDynamicDeploy
(
)
throws
Exception
{
// 1. Build up the model from scratch
BpmnModel
model
=
new
BpmnModel
(
)
;
Process
process
=
new
Process
(
)
;
model
.
addProcess
(
process
)
;
process
.
setId
(
"my-process"
)
;
process
.
addFlowElement
(
createStartEvent
(
)
)
;
process
.
addFlowElement
(
createUserTask
(
"task1"
,
"First task"
,
"fred"
)
)
;
process
.
addFlowElement
(
createUserTask
(
"task2"
,
"Second task"
,
"john"
)
)
;
process
.
addFlowElement
(
createEndEvent
(
)
)
;
process
.
addFlowElement
(
createSequenceFlow
(
"start"
,
"task1"
)
)
;
process
.
addFlowElement
(
createSequenceFlow
(
"task1"
,
"task2"
)
)
;
process
.
addFlowElement
(
createSequenceFlow
(
"task2"
,
"end"
)
)
;
// 2. Generate graphical information
new
BpmnAutoLayout
(
model
)
.
execute
(
)
;
// 3. Deploy the process to the engine
Deployment
deployment
=
activitiRule
.
getRepositoryService
(
)
.
createDeployment
(
)
.
addBpmnModel
(
"dynamic-model.bpmn"
,
model
)
.
name
(
"Dynamic process deployment"
)
.
deploy
(
)
;
// 4. Start a process instance
ProcessInstance
processInstance
=
activitiRule
.
getRuntimeService
(
)
.
startProcessInstanceByKey
(
"my-process"
)
;
// 5. Check if task is available
List
tasks
=
activitiRule
.
getTaskService
(
)
.
createTaskQuery
(
)
.
processInstanceId
(
processInstance
.
getId
(
)
)
.
list
(
)
;
Assert
.
assertEquals
(
1
,
tasks
.
size
(
)
)
;
Assert
.
assertEquals
(
"First task"
,
tasks
.
get
(
0
)
.
getName
(
)
)
;
Assert
.
assertEquals
(
"fred"
,
tasks
.
get
(
0
)
.
getAssignee
(
)
)
;
// 6. Save process diagram to a file
InputStream
processDiagram
=
activitiRule
.
getRepositoryService
(
)
.
getProcessDiagram
(
processInstance
.
getProcessDefinitionId
(
)
)
;
FileUtils
.
copyInputStreamToFile
(
processDiagram
,
new
File
(
"target/diagram.png"
)
)
;
// 7. Save resulting BPMN xml to a file
InputStream
processBpmn
=
activitiRule
.
getRepositoryService
(
)
.
getResourceAsStream
(
deployment
.
getId
(
)
,
"dynamic-model.bpmn"
)
;
FileUtils
.
copyInputStreamToFile
(
processBpmn
,
new
File
(
"target/process.bpmn20.xml"
)
)
;
}
protected
UserTask
createUserTask
(
String
id
,
String
name
,
String
assignee
)
{
UserTask
userTask
=
new
UserTask
(
)
;
userTask
.
setName
(
name
)
;
userTask
.
setId
(
id
)
;
userTask
.
setAssignee
(
assignee
)
;
return
userTask
;
}
protected
SequenceFlow
createSequenceFlow
(
String
from
,
String
to
)
{
SequenceFlow
flow
=
new
SequenceFlow
(
)
;
flow
.
setSourceRef
(
from
)
;
flow
.
setTargetRef
(
to
)
;
return
flow
;
}
protected
StartEvent
createStartEvent
(
)
{
StartEvent
startEvent
=
new
StartEvent
(
)
;
startEvent
.
setId
(
"start"
)
;
return
startEvent
;
}
protected
EndEvent
createEndEvent
(
)
{
EndEvent
endEvent
=
new
EndEvent
(
)
;
endEvent
.
setId
(
"end"
)
;
return
endEvent
;
}
|
For demonstration purposes I created a relatively simple process, but you can imagine the potential if you consider that the POJO-model allows you to use all supported BPMN 2.0 constructs as well as all Activiti-specific extentions.
Using this approach you can create processes at runtime without the need for a design-tool or having to juggle around with XML. It can be used, for example, to create a process-model based on your own “intermediate model” or “building-blocks”, hiding complexity to end-users without sacrificing the richness of the BPMN language.