Skip to main content

Handle Workflow Events in AEM

Hey everybody, it's been almost three months that I have written a post. This weekend, I finally got some time and a use case which I am going to share with you.

We all know workflows play a very important role in the day to day activities of AEM. It is not unheard of that you as a user want to trigger some service/component/scheduler on some of the events in a workflow.

To achieve this, it is necessary that we listen to the workflow events in our code and perform our business logic as that event is triggered. In this post, we will see how we can achieve this using an EventHandler (to know how EventHandler works, see this post).

Since AEM has a rich set of APIs, we are fortunate that it has also an API through which we can listen to workflow-related events.


Below are the steps through which we can listen to workflow events - 

Step #1

Create an Event Handler (WorkflowEventsHandler, in our case) which implements the org.osgi.service.event.EventHandler interface and implement its handleEvent(Event event) method.

Step #2

Since any EventHandler needs some topic to listen to, in our case, we will provide the topic as WorkflowEvent provides an extension of Event that is used for propagating workflow-related information as OSGI events.

Step #3

We will implement handleEvent(Event event) method and get the event topic. We will check if the received topic is of type WorkflowEvent and if it is true then we will proceed further.

Step #4

Now, we will get the event type from the Event object. The event type gives us information about what kind of event our EventHandler has received. Since we can get multiple types of events in a workflow such as WORKFLOW_STARTED, WORKFLOW_COMPLETED, WORKFLOW_RESUMED etc. Based on our requirement, we can implement our business logic.


The complete code for this EventHandler is below -

package org.redquark.demo.core.listeners;

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

import javax.jcr.Session;

import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


 * @author Anirudh Sharma
@Component(service = EventHandler.class, immediate = true, property = {
    + "= This event handler listens to the events that occur in the life cycle of a Workflow",
  EventConstants.EVENT_TOPIC + "=" + WorkflowEvent.EVENT_TOPIC })
public class WorkflowEventsHandler implements EventHandler {

 private final Logger LOG = LoggerFactory.getLogger(this.getClass());

 private ResourceResolverFactory resourceResolverFactory;

 private WorkflowService workflowService;

  * This method returns the workflow session
  * @return {@link WorkflowSession}
 private WorkflowSession getWorkflowSession() {
  try {
   // Creating and getting the service user map
   Map<String, Object> serviceUserMap = new HashMap<>();
   serviceUserMap.put(ResourceResolverFactory.SUBSERVICE, "eventingService");
   // Get the reference of ResourceResolver from the ResourceResolverFactory and
   // the Service User map
   ResourceResolver resourceResolver = resourceResolverFactory.getServiceResourceResolver(serviceUserMap);
   // Adapting ResourceResolver to the Session object
   Session session = resourceResolver.adaptTo(Session.class);
   WorkflowSession workflowSession = workflowService.getWorkflowSession(session);
   return workflowSession;
  } catch (Exception e) {
   LOG.error(e.getMessage(), e);
  return null;

 public void handleEvent(Event event) {"Received event of topic: {}", event.getTopic());
  WorkflowSession workflowSession = null;
  try {
   // Get the workflow session
   workflowSession = getWorkflowSession();
   // Get the received topic
   String topic = event.getTopic();
   // Check if the received topic is of type Workflow event
   if (topic.equals(WorkflowEvent.EVENT_TOPIC)) {
    // Get the type of event
    Object eventType = event.getProperty(WorkflowEvent.EVENT_TYPE);
    // Check for each types of events in a workflow
    if (eventType.equals(WorkflowEvent.WORKFLOW_STARTED_EVENT)) {"Workflow has started");
     String instanceId = (String) event.getProperty(WorkflowEvent.WORKFLOW_INSTANCE_ID);
     try {
      // Get the reference of the Workflow object
      Workflow workflow = workflowSession.getWorkflow(instanceId);
      // Get the workflow data
      WorkflowData workflowData = workflow.getWorkflowData();"Data in workflow: {}", workflowData.getPayload().toString());
     } catch (WorkflowException e) {
      LOG.error(e.getMessage(), e);
    } else if (eventType.equals(WorkflowEvent.WORKFLOW_COMPLETED_EVENT)) {"Workflow has completed");
    } else if (eventType.equals(WorkflowEvent.WORKFLOW_RESUMED_EVENT)) {"Workflow is resumed");
    } else if (eventType.equals(WorkflowEvent.WORKFLOW_ABORTED_EVENT)) {"Workflow is aborted");
    } else if (eventType.equals(WorkflowEvent.WORKFLOW_SUSPENDED_EVENT)) {"Workflow is suspended");
    } else if (eventType.equals(WorkflowEvent.WORKITEM_DELEGATION_EVENT)) {"Workflow is delegated");
    } else {
     LOG.warn("Something is wrong with the workflow");
  } catch (Exception e) {
   LOG.error(e.getMessage(), e);
  } finally {
   if (workflowSession != null) {

Deploy this code on AEM and start testing.


For testing, the following steps can be taken - 

Step #1

Choose a workflow and run it.

Step #2

You should be able to see logs getting printed as - 

2020-03-01 13:25:19.407 INFO [org.redquark.demo.core.listeners.WorkflowEventsHandler] Received event of topic: com/day/cq/workflow/event
2020-03-01 13:25:19.409 INFO [org.redquark.demo.core.listeners.WorkflowEventsHandler] Workflow has started
2020-03-01 13:25:19.412 INFO [org.redquark.demo.core.listeners.WorkflowEventsHandler] Data in workflow: /content/dam/we-retail/en/activities/biking/mountain-biking.jpg


In this post, we saw how can we create an EventHandler and perform our business logic when our required event triggers.

You can find the code to this in my GitHub repository.

I hope you enjoyed this post. Your suggestions and feedback are always welcome. Feel free to befriend me on FacebookTwitter or Linked In or say Hi by email.


Popular posts from this blog

Day 00: AEM Developer Series

Hello everyone! Welcome to this AEM development series. We can all see the revolution of Digital Marketing today. Companies are dying to be a part of it and they have made this a war for the Digital Marketing tools.
Adobe is way ahead in this war and has gained a lot of market capture. They are leaders in the Digital Marketing platforms since 2014-15. One of the flagship product in Adobe's Digital Marketing suite is Adobe Experience Manager (AEM).
Since AEM is in huge demand, the people who know how to develop on AEM are also in huge demand. But developing on AEM is not easy as it is made up of various open-source technologies such as Apache Felix (OSGi), Apache Sling, Apache Oak and Adobe's own technologies like Granite, HTL etc. Learning all these technologies in conjunction can sometimes become confusing and frustrating 😫.
When I first started learning AEM in 2016, I was dumbfounded to see there is so much going on under the hood. I then spent months to gather all the res…

Day 05: Working with Sling Servlets in AEM

Day 03: Setting up AEM Development Environment