Event Handling in AEM

There are multiple ways of handling events in AEM. All the methods have their own pros &cons.

1:- JCR Level Event Handling Using Event Listener

2:- Sling Level using Event Handlers
3:  Workflows & Launchers
4:- Using Scheduler Service

Handling JCR Level Event using Event Listener:-


This is the lowest level event handling which listens to below JCR level events


  • When a node was added
  • When a node was moved
  • When a node was deleted
  • When a property was added to a node
  • When a property was changed
  • When a property was deleted

We can write a custom  handler to handle these  events by implementing javax.jcr.observation.EventListener interface & registering an event using ObservationManager object.

ObservationManager allows for the registration and deregistration of event listeners.It has methods like :-

1:- addEventListener(EventListener listener, int eventTypes, java.lang.String absPath, boolean isDeep, java.lang.String[] uuid, java.lang.String[] nodeTypeName, boolean noLocal) - 

Adds an event listener that listens for the specified eventTypes (a combination of one or more event types encoded as a bit mask value).

listener - an EventListener object.
eventTypes - A combination of one or more event type constants encoded as a bitmask.
absPath - an absolute path.
uuid - Only events whose associated node has one of the UUIDs in this list will be received. If his parameter is null then no UUID-related restriction is placed on events received.
nodeTypeName - Only events whose associated node has one of the node types (or a subtype of one of the node types) in this list will be received. If his parameter is null then no node type-related restriction is placed on events received.
noLocal - if noLocal is true, then events generated by the session through which the listener was registered are ignored. Otherwise, they are not ignored.

2:- removeEventListener(EventListener listener) - 

Deregisters an event listener.

3:- getRegisteredEventListeners() - 

Returns all event listeners that have been registered through this session.


package com.adobe.aem.saurabhaem.core.events;

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

import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.jcr.observation.ObservationManager;

import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Saurabh Kumar
 * 
 * Event Listener that listens to JCR events
 */
@Component(service = EventListener.class, immediate = true)
public class CustomEventListener implements EventListener {

private static final Logger LOGGER = LoggerFactory.getLogger(CustomEventListener.class);
@Reference
private ResourceResolverFactory resolverFactory;

private ResourceResolver resolver;
private Session session;
private ObservationManager observationManager;

/**
* Activate method to initialize stuff
*/
@Activate
protected void activate(ComponentContext componentContext) {
LOGGER.info("Activating the observation");
try {
Map<String, Object> params = new HashMap<>();
params.put(ResourceResolverFactory.SUBSERVICE, "listenerService");
resolver = resolverFactory.getServiceResourceResolver(params);
session = resolver.adaptTo(Session.class);

observationManager = session.getWorkspace().getObservationManager();
    final String[] types = { "nt:unstructured","sling:Folder" };
    final String path = "/content/SaurabhAEM";
    observationManager.addEventListener(
                     this,//handler
                     Event.PROPERTY_ADDED|Event.NODE_ADDED, //binary combination of event types
                     path, //<Path for which you want to observe>
                     true, //is deep
                     null, //uuid filter
                     types, //node types filetr
                     false
                   );
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
@Deactivate
protected void deactivate() {
if(session != null) {
session.logout();
}
}
@Override
public void onEvent(EventIterator events) {
try {
while(events.hasNext()) {
LOGGER.info("A Node or property has been added: {} ", events.nextEvent().getPath() );
}
} catch (Exception e) {
LOGGER.error("Exception occurred", e);
}
}

}

Handling Sling Level Event using Event Handler:-

AT JCR level everything is content, But at sling level everything is a resource, so instead of listening to node/property added/removed we’ll listen to resource changed.

We can achieve event handling at sling level by implementing EventHandler interface in a class.
  • By writing a service class that implements EventHandler interface which must be registered with a service property EventConstants.EVENT_TOPIC (e.g. ReplicationAction.EVENT_TOPIC , PageEvent.EVENT_TOPIC) whose value is the list of topics
  • Implementing handleEvent(Event) method to trigger the job.

package com.adobe.aem.saurabhaem.core.listeners;

import org.apache.sling.api.SlingConstants;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
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;

@Component(service = EventHandler.class,
           property = {
                   Constants.SERVICE_DESCRIPTION + "=Demo to listen on changes in the resource tree",
                   EventConstants.EVENT_TOPIC + "=org/apache/sling/api/resource/Resource/*"
           })
public class SlingEventHandler implements EventHandler {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    public void handleEvent(final Event event) {
        logger.debug("Resource event: {} at: {}", event.getTopic(), event.getProperty(SlingConstants.PROPERTY_PATH));
    }
}

 Using Scheduler Service:-

A scheduler is used to trigger an activity for a particular job, event, or workflow at a set time or periodic interval.
The scheduler can be used in two ways,
  • by registering the job through the scheduler API and
  • by leveraging the whiteboard pattern that is supported by the scheduler.

In most cases the whiteboard pattern is preferred. 
Refer below post to know more about this.

https://aemlearninghub.blogspot.com/2020/05/aem-scheduler.html

Comments

Popular posts from this blog

AEM Scheduler

AEM Sling Servlet