In a pre­vi­ous post, i was explain­ing how to han­dle events gen­er­ally, with sev­eral solu­tions among which:

  • jcr observer
  • sling event handler

a dis­tinc­tion was made between both around the fact jcr observers are low level, but allow to do more. While this is still true :-) this POST will explain how to do a fine-grained jcr event lis­ten­ing through sling event han­dler (and take profit of the sling event han­dling frame­work for those events).

While in jcr, every­thing is con­tent, in sling, every­thing is a resource, so instead of lis­ten­ing to node/property added/removed we’ll lis­ten to resource changed, through the 3 topics :

  1. SlingConstants.TOPIC_RESOURCE_ADDED,
  2. SlingConstants.TOPIC_RESOURCE_CHANGED,
  3. SlingConstants.TOPIC_RESOURCE_REMOVED

Now we should have a han­dler that lis­tens for all the repos­i­tory, for those –very com­mon– events, which will cer­tainly be a per­for­mance killer. Thus we need to fil­ter out this by adding osgi event fil­ter­ing.

This EventConstants.EVENT_FILTER prop­erty takes LDAP fil­ter syn­tax, and has a path attribute, so we can do e.g. (path=/content/my/root/*) or even (path=/content/my/root/*/myNode).

 

A sam­ple code would then be :

@Component
@Service(value=EventHandler.class)
@Properties({
 @Property(name= EventConstants.EVENT_TOPIC,value= {SlingConstants.TOPIC_RESOURCE_ADDED,SlingConstants.TOPIC_RESOURCE_CHANGED, SlingConstants.TOPIC_RESOURCE_REMOVED}),
 @Property(name=EventConstants.EVENT_FILTER,value="(path=/content/my/root/*/myNode)")
})
public class ExampleServiceImpl implements EventHandler { 
 final String[] eventProps = { "resourceAddedAttributes", "resourceChangedAttributes", "resourceRemovedAttributes" };

 public void handleEvent(org.osgi.service.event.Event event) {
  for (String eventProp : eventProps){
   String[] props = (String[])event.getProperty(eventProp);
   …
 }		
}

Pros of this approach vs. Jcr Observer are :

  • this is simpler.
  • this is clus­ter ready.
  • you have the user id infor­ma­tion in it (userid attribute of the event).

A con i can see is that in the par­tic­u­lar case of a bulk save done of N con­cerned resources, your han­dler will be called N times, and then if your han­dler does per­sist, you’ll have a total of N (han­dler per­sis­tences) + 1 (bulk save) per­sis­tences done. While with a jcr observer, you can loop through all the changes of the trans­ac­tion, and do another batch save, reduc­ing the per­sis­tences to 2.