Created
Event Handling in CQ
Event handling can be done in a lot of different ways within CQ, that all have their cost, their impact, and their benefits.
5 ways of doing so are detailed here :
- At the JCR level with observation
- At the Sling level with event handlers and jobs
- At the CQ level with workflows & launchers
- Particular case of scheduled events
- Particular case of POST to the repository
JCR Observer
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
In order to listen to such an event, you have to:
· Manage a live session through which you will listen to the repository
· Decide how and when you listen to it.
· Implement the handler that receive all JCR events filtered by your definition.
A typical usage is
@Component
public class ExampleObservation implements EventListener {
Logger log = LoggerFactory.getLogger(this.getClass());
private Session adminSession;
@Reference
SlingRepository repository;
@Activate
public void activate(ComponentContext context) throws Exception {
log.info("activating ExampleObservation");
try {
adminSession = repository.loginAdministrative(null);
adminSession.getWorkspace().getObservationManager().addEventListener(
this, //handler
Event.PROPERTY_ADDED|Event.NODE_ADDED, //binary combination of event types
"/apps/example", //path
true, //is Deep?
null, //uuids filter
null, //nodetypes filter
false);
} catch (RepositoryException e){
log.error("unable to register session",e);
throw new Exception(e);
}
}
@Deactivate
public void deactivate(){
if (adminSession != null){
adminSession.logout();
}
}
public void onEvent(EventIterator eventIterator) {
try {
while (eventIterator.hasNext()){
log.info("something has been added : {}", eventIterator.nextEvent().getPath());
}
} catch(RepositoryException e){
log.error("Error while treating events",e);
}
}
}
Cautions:
· In this example we don’t care about filtering results, but in real life you’d surely do.
· In lot of cases using JCR Observer is not cluster aware: If the same code is on every cluster node, every change to the cluster farm will trigger the treatment N times.
· Please double-check the performances of your event handling in case it’s called –very – often.
Conclusions
The low level aspect of the JCR observer allows the developer to do more or less whatever he wants, but can bring lot of additional development just for performances, usability and portability. So please use it only when needed.
Event Handler & Jobs
Sling offers within CQ an application level model for handling events, which is called “Sling eventing support”. You can find its deployment in usage in Felix console through web console plugins, bundles and components. The events processed will be those sent by applications, and they will bring application related information. An event must have a topic, that will constitute the “queue” for those events, to which listeners can register.
Here is a simple example:
Application level event sending
@Reference
EventAdmin eventAdmin;
public void createExample(…) throws RepositoryException {
...
final Dictionary<String,Object> properties = new Hashtable();
properties.put(Example.PN_NAME, name);
properties.put(Example.PN_DESC,description);
Event event = new Event(Example.EVENT_TOPIC, properties);
eventAdmin.postEvent(event);
Note here that eventAdmin.postEvent is the asynchronous sending, you can synchronously send your event by using sendEvent API (with the performance risks it can imply).
Handler
This handler is listening to the kind of event above, plus Replication events
@Component
@Service
@Property(name="event.topics",value= {ReplicationAction.EVENT_TOPIC, Example.EVENT_TOPIC})
public class ExampleEventHandler implements EventHandler {
Logger log = LoggerFactory.getLogger(this.getClass());
public void handleEvent(Event event) {
if (event.getTopic().equals(Example.EVENT_TOPIC)){
log.info("Example {}, with description {} has been created...",event.getProperty(Example.PN_NAME),event.getProperty(Example.PN_DESC));
} else if (event.getTopic().equals(ReplicationAction.EVENT_TOPIC)){
ReplicationAction action = ReplicationAction.fromEvent(event);
log.info("User {} has tried to replicate {}",action.getUserId(),action.getPath());
}
}
}
Finally, you can be in the situation where your application wants the guarantee of having its event processed. This is the job use case, in which you will use JobUtil and JobProcessor.
Note that often your listener can be also a JobProcessor, like following :
public void handleEvent(org.osgi.service.event.Event event) {
if (EventUtil.isLocal(event)) {
JobUtil.processJob(event, this);
}
}
CQ topics you can listen to :
Synchronous:
· ForumEvent.Type.TopicAdded
· ForumEvent.Type.PostAdded
Asynchronous:
· Page Events (MSM, CRUD, …) with PageEvent.EVENT_TOPIC and PageEvent.fromEvent API
· Replication event with ReplicationAction.EVENT_TOPIC and ReplicationAction API
· Workflow event (you should look following section)
You’ll have good statistics, monitoring, and configuration at the felix level about jobs and events.
Conclusions
This framework is definitely a good way to go for handling your event, sometimes, it’s even worth surrounding JCR Observation with Sling Eventing in order to manage it more gracefully then.
Workflows
Last but not the least, you can handle events through workflows, with usage of the workflow launcher. This is plainly documented already, easy and fast to write, modular, cluster aware.
A few cautions to keep in mind though:
· There is more processing than in previous approaches.
· Your treatment will be archived and visible among other treatments.
Two good reasons to use workflows are :
· if of course there’s a human step at one stage of the processing.
· if the event handling process should be frequently customized / parameterized by non-admin users.
Scheduling
In case you want to do scheduled treatment, use the sling Scheduler by doing so:
@Component
@Service
@Properties({
@Property(name="scheduler.expression" ,value="0 0/10 * * * ?"),
@Property(name="scheduler.concurrent",boolValue=false)
})
public class ScheduledExample implements Runnable {
Logger log = LoggerFactory.getLogger(this.getClass());
@Reference
ExampleService exampleService;
public void run() {
log.info("My example : {}", exampleService.sayHello());
}
}
For documentation about scheduler.expression format, you have documentation and samples here
Final note : SlingPost processors
Handling a POST write to the repository to do processing at the time the data is written is a common developer task.
Often we see jcr observers handlers while a much simpler approach could be done (in case the POST is actually handled by the SlingPostServlet, which is very often the case): a SlingPostServlet post-processor should be implemented for this.
COMMENTS
-
I am currently working on research paper and part of the curriculum involves this subject matter. Do you have any other posts I can look at regarding this?
-
i like it (y)
-
thanks
-
the article has provided me with a useful set of information on event handling. The details that you have added such as the 5 methods of implementation provided a good read. Keep sharing your views and ideas in this manner.
-
Thanks for keeping us informed
-
Its great to see you taking the time to share this information
-
detailed, comprehensive and useful, thanks!
-
I had been actually even more compared to delighted to seek this web-site. I preferred to I cherish your effort and time having this remarkable read !! I surely savoring each and also every little spot of it and also I've you bookmarked to examine out brand-new stuff you blog. Am I Able To simply say the things a comfort to learn somebody that in truth understands just what theyre speaking of on the web. As well as inspect this: <a href="http://www.financeutile.com">financement participatif</a> and <a href="http://mathsmalin.fr/exercices10/6,aires-et-perimetres.html">exercices aires et périmètres 6eme</a>.
-
I had been actually even more compared to delighted to seek this web-site. I preferred to I cherish your effort and time having this remarkable read !! I surely savoring each and also every little spot of it and also I've you bookmarked to examine out brand-new stuff you blog. Am I Able To simply say the things a comfort to learn somebody that in truth understands just what theyre speaking of on the web. As well as inspect this: <a href="http://www.financeutile.com">financement participatif</a> and <a href="http://mathsmalin.fr/exercices10/6,aires-et-perimetres.html">exercices aires et périmètres 6eme</a>.
-
Part of my job requires me to stay on top of this subject. The article you have written has been beneficial in my research. Thanks a lot.
-
Part of my job requires me to stay on top of this subject. The article you have written has been beneficial in my research. Thanks a lot.
Comments (14)