Triggering a Workflow using Event Listeners in AEM


AEM Version: 6.2
Target Audience: AEM Developers


In AEM 6.2 Workflows, we can trigger a workflow when a DAM Asset is created, modified, or deleted within a given path. In this article, we will explore triggering workflows from our code based on events in the JCR.

Suppose you have a workflow that creates custom renditions of assets in addition to the default AEM renditions, when the asset is under “/content/dam/ProjectName/images/”. You would have set up two launchers for triggering this workflow: one with event type as “Node Create” and one with “Node Modified”. We can also achieve the same functionality through our code, without touching the GUI.


When assets are moved into a certain folder structure in DAM, trigger a workflow that creates a 100px X 100px thumbnail of our image.


Fig 1: Before Moving the asset, no custom thumbnail. Fig 2: Desired result after moving the asset, the new thumbnail.


The intuitive thought is that when an asset is moved, a new node is created in the new location and the old one is deleted. However, experience shows that AEM does not create a new node in the destination folder on Node Move. We know this because the ‘jcr:Created’ property does not change. AEM does not even change the last modified date.

Creation Timestamp Before Moving the Asset Creation Timestamp is the same after moving

Fig 3: Creation Timestamp Before Moving the Asset. Fig 4: Creation Timestamp is the same after moving

Modification Timestamp Before Moving the Asset. Modification Timestamp is the same after moving

Fig 5: Modification Timestamp Before Moving the Asset. Fig 6: Modification Timestamp is the same after moving.

What if we copy the asset?

On copying the asset, a new version of the same is created. This triggers the Node Creation launcher.

No versions before copying the asset Version created after copy-pasting the asset

Fig. 7: No versions before copying the asset. Fig. 8: Version created after copy-pasting the asset.


Event Listeners

AEM supports observation, which enables us to receive notifications of persistent changes to the workspace. A persisted change to the workspace is represented by a set of one or more events. Each event reports a single simple change to the structure of the persistent workspace in terms of an item added, changed, moved or removed. There are thus 7 possible events at the JCR level, viz:

  1. Node Added
  2. Node Moved
  3. Node Modified
  4. Node Removed
  5. Property Added
  6. Property Removed
  7. Property Changed

We connect with the observation mechanism by registering an event listener with the workspace. An event listener is a class implementing the EventListener interface, that responds to the stream of events to which it has been subscribed. An event listener is added to a workspace with:

(A detailed explanation of each parameter is given with the code example in the package as well as the at the end of this article) As defined by the EventListener interface, listener must provide an implementation of the onEvent method:

When an event occurs that falls within the scope of the listener, the repository calls the onEvent method invoking our logic which processes/responds to the event. In our case, we will register an event listener to listen for “Node Moved” events under “/content/dam/images” so that when an asset is moved to that folder, our workflow can be triggered.


When the component is activated, the activate(…) method is called. It contains a call to ObservationManager.addEventListener(…) for registering the event listener. The deactivate(…) method contains logic for deregistering the event listener, and is triggered when the bundle is being stopped.

When the relevant event occurs, the onEvent(…) method is called, which contains logic for processing the event. In our case, we trigger a workflow.

The following is the relevant code from

Download this code (including the workflow):

Build it using

N.B: Creating a workflow is not part of this tutorial, and therefore a ready workflow has been provided in the code package. However, if you want to learn to create workflows, here is an excellent resource: ->



Adobe Consulting Services. (2018, March 20). acs-aem-samples/ at master · Adobe-Consulting-Services/acs-aem-samples. Retrieved from Github:

Day Software AG. (2018, March 20). JCR 2.0: 12 Observation (Content Repository for Java Technology API v2.0). Retrieved from Adobe Docs:

Maven Dependencies Version Issue in AEM

In this post, I will explain package version issues for AEM package dependencies. Here is the scenario where I got this issue:

Issue Description

In one of my project, I had to create a tool for AEM that supports AEM5.6.1 and AEM6.x versions. For some dependencies, these AEM version instances (CQ5.6.1, AEM6.0, AEM6.1, and AEM6.2) needed to use different version of dependencies.

If I used an older version of these dependencies then my bundle did not work in AEM6.2 and remains in installed state. If I used the higher version of these dependencies then my code was not working for the older versions of AEM (CQ5.6.1, AEM6.0, AEM6.1).

Underlying Reason

Versions available for these package dependencies in OSGi container are not same as required by my bundle.
For example, lets take the case of cq-commons dependency.
AEM6.2 supports 5.9.22 version of cq-commons dependency.
AEM6.1 supports 5.8.32 version of cq-commons dependency.
AEM6.0 supports 5.7.12 version of cq-commons dependency.
AEM5.6.1 supports 5.6.4 version of cq-commons dependency.

Because of these different versions some of my java packages ( were not getting resolved.


Here are the list of steps, I followed, to resolve this issue.

Step 1

I have chosen the lowest version of available dependency i.e. 5.6.4 and added a dependency entry in the parent pom.xml file.

Step 2

I defined a property in <properties> section in my parent pom.xml file as mentioned below.
Note: – you can use whatever tag name you want but to make it readable I used this name.

Step 3

I have updated my <maven-bundle-plugin> as shown below-
Here I have used <DynamicImport-Package> tag. Now I have built my project for different AEM versions and it works fine for me in all AEM versions.

Here is the list of questions that may come in your mind:

Q1). What exactly <DynamicImport-Package> tag do?

It will add an entry in MANIFEST.MF file for the packages you mentioned in <bundle.dynamicImport.package> tag. MANIFEST.MF file entry is-

Q2). How bundle start working after using the <DynamicImport-Package> tag?

For answering this question-
First, we need to know about, How OSGi container works?
So, When you deploy your bundle into AEM OSGi container then first OSGi container checks that the available Java Packages versions are compatible with the versions of packages listed in Import-Package tag of your bundle MANIFEST.MF file. If version of Import-Package is not present then you will get an error as written below-

But if you defined these packages in <DynamicImport-Package> tag then OSGi container will not perform the versions checking for these packages and provides the available package definitions to your bundle at runtime.
i.e. using <DynamicImport-Package> is a kind of hack that short-circuits OSGi version checking process.

Note:- It is not recommended to use <DynamicImport-Package> with OSGi container.

Q3). Could we add multiple entries in <bundle.dynamicImport.package> tag?

Yes, you can add multiple packages using comma( “,”) delimiter. for ex.