Listeners
Last updated on 30th September, 2017 by George Taylor
Listeners are services that run because of events occurring within the system.
Event Listeners
As the name suggests, events listen for events occurring from OSGI. The main use case for this is to listen for changes in the jcr:repository. The event listeners should only run against the pre-defined event queues.
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingConstants;
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(value = EventHandler.class)
@Property(name = EventConstants.EVENT_TOPIC, value = "org/apache/sling/api/resource/Resource/*")
public class SimpleResourceListener implements EventHandler {
@Override
public void handleEvent(final Event event) {
This is a very simple listener that will get an event for every change in any of the queues starting org/apache/sling/api/resource/Resource
The SlingConstants class does specify the individual queues that are available for event handlers as
- TOPIC_RESOURCE_ADDED
- A new resource is added to the jcr:repository
- TOPIC_RESOURCE_REMOVED
- A resource has been removed from the jcr:repository
- TOPIC_RESOURCE_CHANGED
- A resource has been changed in the jcr:repository
There are other queues that are available, check in the SlingConstants for the other main queues.
As you can see the listener is a service of type EventHandler, so any calls to the EventHandler manager will filter down to this class. As with the filters the event will be called because of EVERY request to the jcr:repository
The main pieces of information that you get from the event are:
- topic name
- The name of the topic that the message came from.
- Important if you are listening to a number of queues
- property path
- The path that has been added/changed/deleted
- changed attributes
- The attributes that have been changed
- This is only available for change events
Users and groups, while visible in the jcr:explorer are not officially part of the jcr:repository, and while you may sometimes get events fired for changes in a user or group, these are not guaranteed to occur
While it is possible to filter the path the event will run on using the following code
value = "(path=*/my-event-listener-samples/jcr:content)",
description = "[Optional] Event Filters used to further restrict this event handler; Uses LDAP expression against event properties.",
name = EventConstants.EVENT_FILTER,
propertyPrivate = true
I have found it very problematic and sometimes the events i have been expecting don't come through so have tended to test the path as part of the event listener.
Job Listeners
While there isn't really much difference between a job listener and an event listener, the job listener runs against any queue instead of just the defined jcr:repository queues.
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(immediate = true, label = "Job Logger", description = "Custom AEM service for logging jobs", metatype = true, enabled = true)
@Service(value={JobConsumer.class})
@Property(name=JobConsumer.PROPERTY_TOPICS, value="sample/job")
public class MailServiceJob implements JobConsumer {
@Override
public JobResult process(Job job) {
return JobResult.FAILED;
As you can see the only real difference here is that the service is of type JobConsumer. The JobConsumer interface has a single method process(Job) which expects to get a JobResult back.
There are a few responses that will be processed on completion of the job
- OK
- The job has completed and can be removed
- FAILED
- The job has failed and should handle the error handling configuration which will be explained in the ui.apps section
- CANCEL
- The job has been cancelled and should not be retried
- ASYNC
- Processing of the job will be done asynchronously
Jobs won't have any access to the resource resolver or session so will need to get them via a resource resolver factory if required.