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.
The code
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; } |
- Using the BPMN-model, we create a simple process containing a start-event, 2 usertaks, an end-event and the nessecairy flows connecting them.
- We use the BpmnAutoLayout class, found in the activiti-bpmn-autolayout module, to make sure all processes in the BpmnModel have a graphical representation defined.
- Using the new addBpmnModel(…) method on DeploymentBuilder, we make sure out created process gets deployed in the engine.
- We start a new instance of our process by using the process-key we defined in our process.
- Fetch all waiting tasks for the started process and check if the task’s name and assignee are correct.
- To check what the process actually looks like, we save the diagram-image (created based on the BPMN-DI information):

- Finally, save the BPMN 2.0 xml representation of this process. This allows us to, for example, further refine the process in other modeling tools like Activiti Designer.
Possibilities
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.