Bonita Engine Event handlers
An event handler is an extension to the engine that is configured to run when a specified event occurs.
For Subscription editions only. |
Event handlers can help in adding new features to the Platform. You can use them to call your own services when specific events happen like when a case starts, or when a user submits a task.
An event is a change to any object in the database (user, activity, processDefinition,… ). You can create an event handler to track any change to any object in the database and take the appropriate action. For example:
-
Catch PROCESSINSTANCE_CREATED to detect that a process instance has started, and notify the process supervisor.
-
Catch ACTIVITYINSTANCE_STATE_UPDATED to detect that a human task become available, and send email to all the users eligible to perform it.
At the end of this page there is a list of all the events.
Constraints
The platform executes events handlers synchronously at the exact moment the related entity is updated, therefore it executes it in the same thread and same transaction that the one executing the element.
It means that:
-
Events handlers should never block, i.e. no network call, no I/O on the filesystem.
-
Events handlers should never throw exception, if it does, the related element execution will fail, meaning that the transaction is rolled back and the task (for instance) goes to the failed state, which is generally NOT what one wants.
In a cluster environment, Event handlers must be Serializable (implements Serializable and have all its fields serializable or transient) because they are shared with other nodes of the cluster. |
What can be done is:
-
Calling your own services that should be retrieved statically. e.g. pushing information to a queue on which you will poll data.
What should not be done is:
-
Call Rest APIs: Network call can drastically impact Bonita platform performance.
-
Call Bonita platform Java APIs: It will not work, APIs handle the transaction and when the handler is called, we are already in transaction.
If you still want to perform Network call or Bonita platform java APIs calls, you can do it by triggering those calls asynchronously using e.g. a message queue or an ExecutorService.
Please note that the handler is triggered during the execution of a transaction, so it is better to trigger the processing after the current transaction. This can be done by registering a |
Example: deploy an event handler
This example shows an event handler that detects changes in the state of activity instances.
Create a maven project for event handler jar
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.bonitasoft.example</groupId>
<artifactId>event-handler-example</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<maven.compiler.release>17</maven.compiler.release>
<bonita.version>10.3.0</bonita.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.bonitasoft.runtime</groupId>
<artifactId>bonita-runtime-bom</artifactId>
<version>${bonita.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.bonitasoft.engine</groupId>
<artifactId>bonita-server</artifactId>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<!-- Add required additional repositories -->
<repositories>
<repository>
<id>restlet</id>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<url>https://maven.restlet.talend.com/</url>
</repository>
<repository>
<id>terracotta</id>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<url>https://repo.terracotta.org/maven2/</url>
</repository>
</repositories>
</project>
Create event handler class:
Create a class that implements SHandler<SEvent>
.
package org.bonitasoft.example;
import java.util.UUID;
import org.bonitasoft.engine.events.model.SEvent;
import org.bonitasoft.engine.events.model.SHandler;
import org.bonitasoft.engine.events.model.SHandlerExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EventHandlerExample implements SHandler<SEvent> {
private static Logger logger = LoggerFactory.getLogger(EventHandlerExample.class);
private final String identifier = UUID.randomUUID().toString();
public EventHandlerExample() {
}
@Override
public void execute(SEvent event) throws SHandlerExecutionException {
logger.info("ExampleHandler: executing event {}", event.getType());
// add your business logic here
}
@Override
public boolean isInterested(SEvent event) {
logger.info("ExampleHandler - event {} - asks if we are interested in handling this event instance",
event.getType());
// add your business logic here
// for this example purpose, assume we are always interested
return true;
}
@Override
public String getIdentifier() {
return identifier;
}
}
Deploy jar
-
Build event-handle-example-1.0-SNAPSHOT.jar using
mvn clean install
maven command. -
Copy event-handle-example-1.0-SNAPSHOT.jar in
BUNDLE_HOME/server/webapps/bonita/WEB-INF/lib/
folder (for Tomcat bundle)
Register an event handler
An event handler is registered on an event by adding an entry to the appropriate map. The list of handlers registered can be extended in the bonita-tenant-sp-custom.xml
file located in BUNDLE_HOME/setup/platform_conf/initial/tenant_template_engine
folder (or platform_conf/current/tenant_template_engine
if runtime has already been launched):
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- add event handler bean definition -->
<bean id="myEventHandlerExample" class="org.bonitasoft.example.EventHandlerExample">
</bean>
<bean id="eventHandlers" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="targetMapClass">
<value>java.util.HashMap</value>
</property>
<property name="sourceMap">
<map>
<entry key="PROCESSINSTANCE_STATE_UPDATED" value-ref="myEventHandlerExample"/>
</map>
</property>
</bean>
</beans>
Test it
Restart web server and run a basic process and check bonita log file in folder tomcat/logs:
INFOS: THREAD_ID=78 | HOSTNAME=gt | ExampleHandler: event PROCESSINSTANCE_STATE_UPDATED - asks if we are interested in handling this event instance
...
INFOS: THREAD_ID=78 | HOSTNAME=gt | ExampleHandler: executing event PROCESSINSTANCE_STATE_UPDATED
Filter an event
An event handler contains a filter, isInterested
, which detects the relevant instances of the event.
The example below shows how to use the State Id of a flow node to filter for a particular state (in this case, failed).
Flownode State Ids are defined in the subclasses of org.bonitasoft.engine.core.process.instance.api.states.FlowNodeState
.
There is no exhaustive list; the set of states is extensible without notice.
@Override
public boolean isInterested(SEvent event) {
boolean isInterested = false;
// Get the object associated with the event
Object eventObject = event.getObject();
// Check that event is related to a task
if (eventObject instanceof SFlowNodeInstance) {
SFlowNodeInstance flowNodeInstance = (SFlowNodeInstance) eventObject;
// Verify that state of the task is failed. See
// FailedActivityStateImpl
isInterested = (flowNodeInstance.getStateId() == 3);
}
return isInterested;
}
Event handlers are recursive, that is, if an event handler itself modifies something and triggers an event, the relevant event handler is called. This means you might need to include loop detection in your event handler.
Event list
This is a snapshot of the events used in the Engine.
Service |
Events |
ActivityInstanceServiceImpl |
ACTIVITYINSTANCE_CREATED, HUMAN_TASK_INSTANCE_ASSIGNEE_UPDATED, ACTIVITYINSTANCE_STATE_UPDATED, ACTIVITY_INSTANCE_TOKEN_COUNT_UPDATED, HIDDEN_TASK_CREATED, HIDDEN_TASK_DELETED, PENDINGACTIVITYMAPPING_CREATED, PENDINGACTIVITYMAPPING_DELETED |
ActorMappingServiceImpl |
ACTOR_CREATED, ACTOR_DELETED, ACTOR_UPDATED, ACTOR_MEMBER_CREATED, ACTOR_MEMBER_DELETED |
CategoryServiceImpl |
CATEGORY_CREATED, CATEGORY_DELETED, CATEGORY_UPDATED |
CommandServiceImpl |
COMMAND_CREATED, COMMAND_DELETED, COMMAND_UPDATED |
SCommentServiceImpl |
COMMENT_CREATED, COMMENT_DELETED |
ConnectorInstanceServiceImpl |
CONNECTOR_INSTANCE_CREATED, CONNECTOR_INSTANCE_DELETED, CONNECTOR_INSTANCE_STATE_UPDATED, CONNECTOR_INSTANCE_UPDATED |
DependencyServiceImpl |
DEPENDENCY_CREATED, DEPENDENCYMAPPING_CREATED, DEPENDENCY_DELETED, DEPENDENCYMAPPING_DELETED, DEPENDENCY_UPDATED, DEPENDENCYMAPPING_UPDATED |
DocumentMappingServiceImpl |
DOCUMENTMAPPING_CREATED, DOCUMENTMAPPING_DELETED, DOCUMENTMAPPING_UPDATED |
SEventInstanceServiceImpl |
EVENT_INSTANCE_CREATED, EVENT_TRIGGER_INSTANCE_CREATED, EVENT_TRIGGER_INSTANCE_DELETED, MESSAGE_INSTANCE_CREATED, MESSAGE_INSTANCE_DELETED, MESSAGE_INSTANCE_UPDATED |
ExternalIdentityMappingServiceImpl |
EXTERNAL_IDENTITY_MAPPING_CREATED, EXTERNAL_IDENTITY_MAPPING_DELETED |
FlowNodeInstanceServiceImpl |
FLOWNODE_INSTANCE_DELETED |
GatewayInstanceServiceImpl |
GATEWAYINSTANCE_CREATED, GATEWAYINSTANCE_HITBYS_UPDATED, GATEWAYINSTANCE_STATE_UPDATED |
IdentityServiceImpl |
GROUP_CREATED, GROUP_DELETED, GROUP_UPDATED, METADATA_CREATED, METADATA_DELETED, METADATA_UPDATED, METADATAVALUE_CREATED, METADATAVALUE_DELETED, METADATAVALUE_UPDATED, ROLE_UPDATED, ROLE_CREATED, ROLE_DELETED, USER_UPDATED, USER_CREATED, USER_DELETED, USER_CONTACT_INFO_UPDATED, USER_CONTACT_INFO_CREATED, USER_CONTACT_INFO_DELETED, USERMEMBERSHIP_UPDATED, USERMEMBERSHIP_CREATED, USERMEMBERSHIP_DELETED |
JobServiceImpl |
JOB_DESCRIPTOR_CREATED, JOB_DESCRIPTOR_DELETED, JOB_PARAMETER_CREATED, JOB_PARAMETER_DELETED, JOB_LOG_CREATED, JOB_LOG_DELETED |
JobWrapper |
JOB_COMPLETED, JOB_EXECUTING |
ProcessDefinitionServiceImpl |
PROCESSDEFINITION_CREATED, PROCESSDEFINITION_DELETED, PROCESSDEFINITION_DEPLOY_INFO_UPDATED, PROCESSDEFINITION_IS_DISABLED_UPDATED, PROCESSDEFINITION_IS_ENABLED_UPDATED, PROCESSDEFINITION_IS_RESOLVED_UPDATED |
ProcessInstanceServiceImpl |
PROCESS_INSTANCE_CATEGORY_STATE_UPDATED, PROCESSINSTANCE_CREATED, PROCESSINSTANCE_DELETED, PROCESSINSTANCE_STATE_UPDATED, PROCESSINSTANCE_UPDATED |
ProfileServiceImpl |
PROFILE_CREATED, PROFILE_DELETED, PROFILE_UPDATED, PROFILE_MEMBER_CREATED, PROFILE_MEMBER_DELETED |
SupervisorMappingServiceImpl |
SUPERVISOR_CREATED, SUPERVISOR_DELETED |