Tech Blog

Facebook Icon Twitter Icon Linkedin Icon

AnyMind Group

Facebook Icon Twitter Icon Linkedin Icon

[Tech Blog] Introduction to Camunda BPM

Hello! I’m Leo and I’m backend engineer @ AnyTag team

In this article I’ll tell about BPMN (Business Process Model and Notation) with a small demo.

In complex business process with many if-else clauses, switches and branches, which is need to be updated very hard not just make any change but even understand how does it work. One of the way to make it clear is BPMN. This is the kind of formalised graphical notation, visual representation of business process. It can be used both by engineers and managers.

For example, we have a business process, which can be split into separate logic elements. If the process fails on one element, it should be possible to rerun it from failed place any number of times. We also want to know which process is succeed, or if it failed we want to know where and why. It’s perfect, for example, for processes that frequently changing with complex logic.

One of the most common implementation of BPMN engine is Camunda. It includes engine, visual modeler and control instruments, tools for collaboration editing and managing, get heat maps of processes and more.

Let’s try to implement some example. We can generate example project with camunda using https://start.camunda.com. In this example use default settings: H2 Database, Java11, Maven. But we also can use it with Postgres, Kotlin and Gradle.

Then we can open it with IDE, run and check if everything is okay. Open localhost:8080 in browser and you’ll get an admin control panel. By default login and password are generated as demo/demo, but you can change it in application.yaml in camunda.bpm.admin-user or move to another place to make in more secure. In generated example by default we have one BPMN process src/main/resources/process.bpmn. Let’s try to run it from UI. localhost:8080 → Tasklist → Start Process → camunda_example-process, enter any business key. Now check its status in Camunda: go back to localhost:8080 → Cockpit → Running process instances → camunda_example-process and we can see a graphical representation of this example schema and all information about that process. We can also manage this process here.

Let’s create our own process. Download Camunda Modeler from official website: https://camunda.com/download/modeler/ and install. With this tool we can create and edit bpmn schemas easily. Create a new BPMN and call it payment_check.bpmn.

The main groups elements in BPMN are:

  • Flow objects: events, activities, gateways
  • Connecting objects: Sequence flow, message flow, association
  • Swim lanes: pool, lane
  • Artifacts: Data object, group, annotation

We have an initial state, finite state, intermediate states (which is used for throwing exceptions), tasks. Each process starts from initial state, and ends when finite state reached. Between them, we have connected tasks, gateways and intermediate states. Task is an action, which include groovy code or call delegate class to interact with code of application.

Let’s add initial state element, task and final element, and connect them. So, we have something like in generated example. Set Id of this process: shipment-process

Create a delegate class ShipmentDelegate in src/main/java/com/example/workflow/service/

package com.example.workflow.service;

import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Component;

@Component
public class ShipmentDelegate implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) throws Exception {
        System.out.println("An item shipped to a customer");
    }
}

Then go back to Modeler, press on task, press on wrench sign and choose Service task. Then open properties panel, Details → Implementation → Java class and paste com.example.workflow.service.ShipmentDelegate. Also we need to execute this process not only from UI, so: create service:

package com.example.workflow.service;

import org.camunda.bpm.engine.ProcessEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


@Component
public class ShipmentService {
    @Autowired
    private ProcessEngine processEngine;

    public void shipItem() {
        processEngine.getRuntimeService().startProcessInstanceByKey("shipment-process");
    }
}

and rest-controller

package com.example.workflow.controller;

import com.example.workflow.service.ShipmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
class ShipmentController {
    @Autowired
    private ShipmentService shipmentService;

    @GetMapping("/ship_item/")
    public String shipItem() {

        shipmentService.shipItem();
        return "Shipment request received";
    }
}

now we can run our project and call curl localhost:8080/ship_item/ So, we can check in logs that item was shipped.

Let’s add into out process a bit of complexity and check if we received payment before shipment. We will add a context variable here and change code a bit.

Add parameter to method ShipmentController:

@GetMapping("/ship_item/{isPaid}")
public String shipItem(@PathVariable boolean isPaid) {
    shipmentService.shipItem(isPaid);
    return "Shipment request received";
}

and now we run process with variable as parameter. It also could be added as map of variables. We can set and get variables while process run.

public void shipItem(boolean isPaid) {
    processEngine
            .getRuntimeService()
            .createProcessInstanceByKey("payment-process")
            .setVariable("isPaid", isPaid).execute();
}

Add extra delegate:

@Component
public class ShipmentDeniedDelegate implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) throws Exception {
        System.out.println("Shipment denied");
    }
}

Then we need to extend out bpmn schema. Add gateway, extra activity task, and connect in this way.

Also, set condition ${isPaid == true}

and set other connection flow as default.

We can run demo with curl http://localhost:8080/ship_item/true and curl http://localhost:8080/ship_item/false check logs.

BPMN is great instrument to make your process clear, visually represented and easily maintainable. With platforms like Camunda you also can track processes, manage manually if need and optimize.

Latest News