Blogs > Event Handler and Event Listener in AEM

AEM Sites

Event Handler and Event Listener in AEM

Infodales Tech Solutions | November 28, 2024

Overview

An Event Handler manages events at the Sling level, while an Event Listener handles events at the JCR level. Both are responsible for executing actions when an event occurs. .

Event Handler (OSGi Event Handler) in AEM:

An OSGi Event Handler listens for OSGi events, including resource modifications, workflow events, and system events. It is implemented using org.osgi.service.event.EventHandler and registered via OSGi service properties.

Syntax

                        
                            @Component(service = EventHandler.class,
                            immediate = true,
                            property = {
                            EventConstants.EVENT_TOPIC + "=org/apache/sling/api/resource/Resource/ADDED",
                            EventConstants.EVENT_TOPIC + "=org/apache/sling/api/resource/Resource/REMOVED",
                            EventConstants.EVENT_FILTER + "+(path=/content/we-retail/us/en/*)"
                            })
                            public class SampleEventHandler implements EventHandler {
                        
                    

How to create Event Handler In AEM

                        
                            package com.sample.core.listeners;


                            import org.apache.sling.api.SlingConstants;
                            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,
                            immediate = true,
                            property = {
                                  EventConstants.EVENT_TOPIC + "=org/apache/sling/api/resource/Resource/ADDED",
                                  EventConstants.EVENT_TOPIC + "=org/apache/sling/api/resource/Resource/REMOVED",
                                           EventConstants.EVENT_FILTER + "+(path=/content/we-retail/us/en/*)"
                            })
                            public class SampleEventHandler implements EventHandler {
                            private final Logger logger = LoggerFactory.getLogger(getClass());
                            @Override
                            public void handleEvent(Event event) {
                            logger.info("Event Topic" + event.getTopic(),event.getProperty(SlingConstants.PROPERTY_PATH));
                            }
                            }
                            
                        
                    

Logs

Event-Listener-image

In the example above, we created a class named SampleEventHandler, which implements the EventHandler interface and overrides the handleEvent method. Additionally, we have defined the event topics that should trigger the event.

Event Listener (JCR Event Listener) in AEM

A JCR Event Listener listens for changes in the JCR repository, such as node additions, modifications, or deletions. It is implemented using javax.jcr.observation.EventListener and registered via ObservationManager.

Syntax

                        
                            @Component(service = EventListener.class,
                            immediate = true)
                            public class SampleEventListener implements EventListener {                          
                        
                    

How to create Event Listener In AEM

                        
                            package com.sample.core.listeners;
                            import org.apache.sling.api.resource.LoginException;
                            import org.apache.sling.api.resource.ResourceResolver;
                            import org.apache.sling.api.resource.ResourceResolverFactory;
                            import org.osgi.service.component.annotations.Activate;
                            import org.osgi.service.component.annotations.Component;
                            import org.osgi.service.component.annotations.Modified;
                            import org.osgi.service.component.annotations.Reference;
                            import org.slf4j.Logger;
                            import org.slf4j.LoggerFactory;
                            import javax.jcr.RepositoryException;
                            import javax.jcr.Session;
                            import javax.jcr.observation.Event;
                            import javax.jcr.observation.EventIterator;
                            import javax.jcr.observation.EventListener;
                            import java.util.HashMap;
                            import java.util.Map;
                            
                            
                            @Component(service = EventListener.class,
                            immediate = true)
                            public class SampleEventListener implements EventListener {
                            private final Logger logger = LoggerFactory.getLogger(getClass());
                            
                            
                            @Reference
                            private ResourceResolverFactory resourceResolverFactory;
                            @Activate
                            @Modified
                            protected void Activate() throws LoginException, RepositoryException {
                               Map map = new HashMap<>();
                               map.put(ResourceResolverFactory.SUBSERVICE,"test");
                                ResourceResolver resourceResolver = resourceResolverFactory.getServiceResourceResolver(map);
                                Session session = resourceResolver.adaptTo(Session.class);
                                session.getWorkspace().getObservationManager().addEventListener(this,
                                      Event.PROPERTY_ADDED | Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_CHANGED,
                                      "/content/we-retail/us/en",
                                      true,
                                      null,null,false
                                      );
                                logger.info("--Property Changed Or removed --");
                            }
                            @Override
                            public void onEvent(EventIterator events) {
                               logger.info("Event Listener Called");
                               while (events.hasNext()){
                                  try {
                                     logger.info("Event Path is " + events.nextEvent().getPath());
                                  } catch (RepositoryException e) {
                                     throw new RuntimeException(e);
                                  }
                               }
                            }
                            }
                                                
                        
                    

In the example above, we created SampleEventListener, which implements the EventListener interface and overrides the onEvent method. Using ObservationManager, we can add an event listener and define event types such as PROPERTY_ADDED, PROPERTY_CHANGED, and NODE_ADDED to trigger the event.

ResourceChangeListener in AEM

The ResourceChangeListener in AEM listens for changes in Sling resources (e.g., content modifications in /content, configuration updates in /conf, etc.). It is more efficient than JCR Event Listeners because it operates at the Sling level rather than directly in the JCR repository.

Syntax

                        
                            @Component(service = ResourceChangeListener.class,
                            immediate = true,
                            property = {
                                  ResourceChangeListener.PATHS + "=" + "/content/we-retail/us/en",
                                  ResourceChangeListener.CHANGES + "=" + "ADDED",
                                  ResourceChangeListener.CHANGES + "=" + "CHANGED",
                                  ResourceChangeListener.CHANGES + "=" + "REMOVED"
                            })
                            @ServiceDescription("SampleResourceChangeListener")
                            public class SampleResourceChangeListener implements ResourceChangeListener {
                                                
                        
                    

How to create ResourceChangeListener In AEM

                        
                            package com.sample.core.listeners;
                            import org.apache.sling.api.resource.observation.ResourceChange;
                            import org.apache.sling.api.resource.observation.ResourceChangeListener;
                            import org.osgi.service.component.annotations.Component;
                            import org.osgi.service.component.propertytypes.ServiceDescription;
                            import org.slf4j.Logger;
                            import org.slf4j.LoggerFactory;
                            
                            
                            import java.util.List;
                            
                            
                            
                            
                            @Component(service = ResourceChangeListener.class,
                            immediate = true,
                            property = {
                                  ResourceChangeListener.PATHS + "=" + "/content/we-retail/us/en",
                                  ResourceChangeListener.CHANGES + "=" + "ADDED",
                                  ResourceChangeListener.CHANGES + "=" + "CHANGED",
                                  ResourceChangeListener.CHANGES + "=" + "REMOVED"
                            })
                            @ServiceDescription("SampleResourceChangeListener")
                            public class SampleResourceChangeListener implements ResourceChangeListener {
                            private final Logger logger = LoggerFactory.getLogger(getClass());
                            @Override
                            public void onChange( List list) {
                             list.forEach(resourceChange -> {
                                 logger.info("Event Type = {}", resourceChange.getType());
                                 logger.info("Event Path = {}", resourceChange.getPath());
                                 logger.info("Event External = {}", resourceChange.isExternal());
                             });
                            }
                            }                                                              
                      
                    
resource-listener-image

In the example above we have created the SampleResourceChangeListener which implements ResourceChangeListener and overrides onChange event , the event will get triggered when we change , add , remove the Node .


Yash Sakharkar | AEM Developer
LinkedIn Email