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
This is the lowest level event handling which listens to below JCR level events
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.
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);
}
}
}
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));
}
}
https://aemlearninghub.blogspot.com/2020/05/aem-scheduler.html
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
Post a Comment