How to create Activiti Event Listener with Spring Boot Example

Activiti provides event mechanism that allows us to get notified when various events occur within the engine. In this tutorial, we’re gonna look at an example that uses Activiti Event Listener with Spring Boot.

Related Posts:
Introduction to Activiti – a Java BPM Engine
Activiti Message Event with Spring Boot Example

I. Activiti Event Listener Overview

1. Implementation

The first thing we have to do is implementing org.activiti.engine.delegate.event.ActivitiEventListener interface. You can find all supported event types at Activiti User Guide.


public class MyEventListener implements ActivitiEventListener {

	@Override
	public void onEvent(ActivitiEvent event) {
		switch (event.getType()) {

		case PROCESS_STARTED:
			// ...
			break;

		case PROCESS_COMPLETED:
			// ...
			break;

		// other EVENT_TYPE...

		default:
			break;
		}
	}

	@Override
	public boolean isFailOnException() {
		
		return false;
	}
}

isFailOnException() method will be called when onEvent() method throws an exception. Returning false means the exception is ignored.

All events dispatched are a subtype of org.activiti.engine.delegate.event.ActivitiEvent.
From the event, we can get (if available) type, executionId, processInstanceId and processDefinitionId.

2. Registering

The second thing we do is to register the ActivitiEventListener implementation above.

2.1 At runtime

We can add or remove event listener to the engine by using RuntimeService‘s methods:


// Add event-listener which will be notified of ALL events by the dispatcher.
void addEventListener(ActivitiEventListener listenerToAdd);

// Add event listener which will only be notified when given event types occur.
void addEventListener(ActivitiEventListener listenerToAdd, ActivitiEventType... types);

// Remove event listener from this dispatcher.
void removeEventListener(ActivitiEventListener listenerToRemove);

2.2 in the BPMN XML

We can add event listener to a specific process definition. The listeners will only be called for events related to process instances that are started with that process definition.


<process id="simpleProcess" name="Simple Process">
	<extensionElements>
		<activiti:eventListener
			class="com.javasampleapproach.activiti.eventlistener.listener.MyEventListener" />
	</extensionElements>
	...
</process>
Notes for registering in process definition:
– Event listener can only be declared as a child-element of the extensionElements inside process definition, and cannot be defined on any individual activity in the process.
– There is only a single instance of that class to be created. Make sure the listener implementations do not rely on member-fields and ensure safe usage from multiple threads/contexts.

II. Practice

1. Technology

– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.4.RELEASE
– Spring Boot: 1.5.3.RELEASE

2. Project Overview

activiti-eventlistener-example

We will start the Process by message, then complete 2 Tasks to see how EvenListener works.

activiti-eventlistener-structure

MyEventListener is an implementation of ActivitiEventListener that contains onEvent() method to be called everytime an event (related to Process) occurs.
– Process definition will be written under XML format in process/process.bpmn20.xml file.
MyService provides service methods for Controller such as: startProcess(), getTasks(), completeTask(). Those functions can be done with help of some @Autowired objects which are instances of these classes:
+ RuntimeService
+ TaskService
MyController is a REST Controller which has request mapping methods for RESTful requests such as: /startprocess, /tasks, /completetask.
pom.xml contains dependencies for:
+ Activiti Spring Boot Starter Basic
+ Spring Boot Starter Web
+ H2 database: Activiti Engine needs a database to store its data. By default, it will connect to an in-memory H2 database.

3. Step by step

3.1 Create Spring Boot project

Using Spring Tool Suite/Eclipse to create Project and add Dependencies to pom.xml file:


<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
</dependency>

<dependency>
	<groupId>org.activiti</groupId>
	<artifactId>activiti-spring-boot-starter-basic</artifactId>
	<version>5.22.0</version>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

3.2 Create implementation of ActivitiEventListener


package com.javasampleapproach.activiti.eventlistener.listener;

import org.activiti.engine.delegate.event.ActivitiEvent;
import org.activiti.engine.delegate.event.ActivitiEventListener;

public class MyEventListener implements ActivitiEventListener {

	@Override
	public void onEvent(ActivitiEvent event) {
		switch (event.getType()) {
		case PROCESS_STARTED:
			System.out.println("New Process Instance has been started.");
			break;

		case PROCESS_COMPLETED:

			String message = (String) event.getEngineServices().getRuntimeService().getVariable(event.getExecutionId(),
					"message");

			System.out.println("Process (started by \"" + message + "\") has been completed.");
			break;

		case VARIABLE_CREATED:
			System.out.println("New Variable was created.");
			System.out.println(">> All Variables in execution scope: "
					+ event.getEngineServices().getRuntimeService().getVariables(event.getExecutionId()));
			break;

		case TASK_ASSIGNED:
			System.out.println("Task has been assigned.");
			break;

		case TASK_CREATED:
			System.out.println("Task has been created.");
			break;

		case TASK_COMPLETED:
			System.out.println("Task \""
					+ event.getEngineServices().getHistoryService().createHistoricTaskInstanceQuery()
							.orderByHistoricTaskInstanceEndTime().asc().list().get(0).getName()
					+ "\" has been completed.");
			break;

		default:
			break;
		}
	}

	@Override
	public boolean isFailOnException() {
		System.out.println("inside isFailOnException()");
		return false;
	}

}

3.3 Define Process

Under src/main/resources, create processes folder and add process.bpmn20.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
	xmlns:activiti="http://activiti.org/bpmn" targetNamespace="Examples">

	<message id="messageId" name="MyMessage" />

	<process id="simpleProcess" name="Simple Process">

		<extensionElements>
			<activiti:eventListener
				class="com.javasampleapproach.activiti.eventlistener.listener.MyEventListener" />
		</extensionElements>

		<startEvent id="start">
			<messageEventDefinition messageRef="messageId" />
		</startEvent>

		<sequenceFlow sourceRef="start" targetRef="theTask" />

		<userTask activiti:async="true" id="theTask" name="Task"
			activiti:assignee="${person}">
			<documentation>
				Do the task.
			</documentation>
		</userTask>

		<sequenceFlow sourceRef="theTask" targetRef="anotherTask" />

		<userTask activiti:async="true" id="anotherTask" name="Another Task"
			activiti:assignee="${person}">
			<documentation>
				Do Another task.
			</documentation>
		</userTask>

		<sequenceFlow sourceRef="anotherTask" targetRef="theEnd" />
		<endEvent id="theEnd" />
	</process>

</definitions>

3.4 Create Service Class


package com.javasampleapproach.activiti.eventlistener.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MyService {

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private TaskService taskService;

	public String startProcess(String message, String assignee) {

		Map variables = new HashMap();
		variables.put("message", message);
		variables.put("person", assignee);

		runtimeService.startProcessInstanceByMessage(message, variables);

		return "Process started";
	}

	public List getTasks(String assignee) {
		return taskService.createTaskQuery().taskAssignee(assignee).list();
	}

	public void completeTask(String taskId) {
		taskService.complete(taskId);
	}
}

3.5 Create Controller Class


package com.javasampleapproach.activiti.eventlistener.controller;

import java.util.List;

import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.javasampleapproach.activiti.eventlistener.service.MyService;

@RestController
public class MyController {

	@Autowired
	private MyService myService;

	@RequestMapping(value = "/startprocess/{message}")
	public String startProcessInstance(@PathVariable("message") String message, @RequestParam String assignee) {
		return myService.startProcess(message, assignee);
	}

	@RequestMapping(value = "/tasks/{assignee}")
	public String getTasks(@PathVariable("assignee") String assignee) {
		List tasks = myService.getTasks(assignee);
		return tasks.toString();
	}

	@RequestMapping(value = "/completetask")
	public String completeTask(@RequestParam String id) {
		myService.completeTask(id);
		return "Task with id " + id + " has been completed!";
	}
}

3.6 Run & Check Result

– Config maven build:
clean install
– Run project with mode Spring Boot App
– Check results by open your browser and send request:

Request 1: Start Process by MyMessage and assign tasks to John
http://localhost:8080/startprocess/MyMessage?assignee=John


New Variable was created.
>> All Variables in execution scope: {person=John}
New Variable was created.
>> All Variables in execution scope: {person=John, message=MyMessage}
New Process Instance has been started.
Task has been assigned.
Task has been created.

Request 2: show tasks of John
http://localhost:8080/tasks/John


[Task[id=11, name=Task]]

Request 3: complete Task
http://localhost:8080/completetask?id=11


Task "Task" has been completed.
Task has been assigned.
Task has been created.

“New Task” has been assigned and created.

Request 4: show tasks of John
http://localhost:8080/tasks/John


[Task[id=15, name=Another Task]]

Request 5: complete New Task
http://localhost:8080/completetask?id=15


Task "Another Task" has been completed.
Process (started by "MyMessage") has been completed.

III. Source Code

SpringActivitiEventListener



By grokonez | May 19, 2017.

Last updated on May 5, 2021.



Related Posts


2 thoughts on “How to create Activiti Event Listener with Spring Boot Example”

  1. This helped me get past a MAJOR bug as I looked to use Activiti V6 and ultimately Activiti V5.22.0. Thank you for the excellent post!

Got Something To Say:

Your email address will not be published. Required fields are marked *

*