Event Handling

Event handling can be done in different ways within CQ, that all have their cost, their impact, and their benefits.

  • Event Listener - At the JCR level with observation.
  • Event Handler - At the Sling level with event handlers and jobs
  • At the AEM level with work­flows & launchers.
  • Java classes implementing Runnable interface and scheduled using cron expressions.

To view the current snapshot of events you should check the events logs at http://host:port/system/console/events.


Interview Questions

Note: For more on Event Handling watch this video

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
@Service(value = EventHandler.class)
@Component(immediate = true)
@Property(name = "event.topics", value = ReplicationAction.EVENT_TOPIC)
public class ReplicationLogger implements EventHandler, JobProcessor {
 private static final Logger LOGGER = LoggerFactory.getLogger(ReplicationLogger.class);
 @Reference
 private JcrResourceResolverFactory jcrResourceResolverFactory;
 @Override
 public void handleEvent(Event event) {
   LOGGER.info("********handling event");
   process (event);
 }
 @Override
 public boolean process(Event event) {
  LOGGER.info("********processing job");
  ReplicationAction action = ReplicationAction.fromEvent(event);
  ResourceResolver resourceResolver = null;
  if (action.getType().equals(ReplicationActionType.ACTIVATE)) {
  try {
   resourceResolver = jcrResourceResolverFactory.getAdministrativeResourceResolver(null);
  final PageManager pm = resourceResolver.adaptTo(PageManager.class);
  final Page page = pm.getContainingPage(action.getPath());
  if(page != null) {
   LOGGER.info("********activation of page {}", page.getTitle());
  }
 }
 catch (LoginException e) {
   e.printStackTrace();
  }
 finally {
  if(resourceResolver != null && resourceResolver.isLive()) {
   resourceResolver.close();
  }
  }
 }
  return true;
 }

We need to implement org.osgi.service.event.EventHandler interface. more

We can achieve event handling at JCR level by implementing EventListener interface in a class. JCR Observer is the lowest-level event handling in CQ. As its name indicates it, is at JCR level and allows to listen to JCR-level events, gathered in sets (corresponding to persistence transactions). javax.jcr.observation.Event lists following types:

  • Event.NODE_ADDED
  • Event.NODE_MOVED
  • Event.NODE_REMOVED
  • Event.PERSIST
  • Event.PROPERTY_ADDED
  • Event.PROPERTY_CHANGED
  • Event.PROPERTY_REMOVED
@Component
public class PropertyListener implements EventListener {
 private final Logger LOGGER = LoggerFactory.getLogger(TitlePropertyListener.class);
 @Reference
 private SlingRepository repository;
 private Session session;
 private ObservationManager observationManager;
 protected void activate(ComponentContext context) throws Exception {
  session = repository.loginService(null, repository.getDefaultWorkspace());
  observationManager = session.getWorkspace().getObservationManager();
  observationManager.addEventListener(this, Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED, "/", true, null, null, true);
  LOGGER.info("********added JCR event listener");
 }
 protected void deactivate(ComponentContext componentContext) {
  try {
   if (observationManager != null) {
    observationManager.removeEventListener(this);
    LOGGER.info("********removed JCR event listener");
   }
  }
  catch (RepositoryException re) {
   LOGGER.error("********error removing the JCR event listener", re);
  }
  finally {
   if (session != null) {
    session.logout();
    session = null;
   }
  }
 }
 public void onEvent(EventIterator it) {
  while (it.hasNext()) {
   Event event = it.nextEvent();
   try {
    LOGGER.info("********new property event: {}", event.getPath());
    Property changedProperty = session.getProperty(event.getPath());
    if (changedProperty.getName().equalsIgnoreCase("jcr:title") && !changedProperty.getString().endsWith("!")) {
     changedProperty.setValue(changedProperty.getString() + "!");
     session.save();
    }
   }
   catch (Exception e) {
    LOGGER.error(e.getMessage(), e);
   }
  }
 }
}

The ObservationManager object acquired via Workspace.getObservationManager(). Allows for the registration and deregistration of event listeners.Observation Manager Api is omni present in AEM. 200 thousand event it can handle in entire life time. 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.
Event handler Event listener
It is at the Sling level with event handlers and jobs It is at the JCR level with observation.
org.osgi.service.event.EventHandler interface javax.jcr.observation.EventListener interface
override handleEvent(Event) method. override onEvent(EventIterator ) method

Event subscriber need to subscribe event.topic property to an Event Handler in the OSGi Event Admin service.