Thursday 26 February 2015

Be RESTful on AEM6

JAX-RS(JSR311) is the JCP driven specification for creating REST styled webservices in java. There are use cases where content/service needs to be exposed to third parties, though AEM itself is rest driven there is no support for creating RESTful services. 

Jersey and OSGI can be brought together to provide restful service on AEM platform. jax-rs-connector is one such project that does this job and allows publishing Resources as OSGI service, the good thing is you can use all existing OSGI service via DI annotation @References.

The connector has a publisher bundle which  does this job via ServiceTracker mechanism i.e.  it tracks services having JAX-RS annotation(@Path, @Provider ) and hooks them into jersey i.e publishes as restful service.

AEM Implementation

To use it in AEM one needs to do following-:
 Clone the github project jax-rs-connector  and build the project or download jars from http://search.maven.org/#search|ga|1|g%3A%22com.eclipsesource.jaxrs%22 .
  • Install jersey-all jar via osgi console.
  • Install publisher jar and it's dependency  (JAX-RS Security Provider jar)
  • Install (JAX-RS Gson Provider, Gson jar) for JSON response. (Optional)
Make sure all the installed bundles are active.



Now add some Resource as OSGI Service, as below :


1:    @Service   
2:    @Component(metatype = false)   
3:    @Path("/helloservice")   
4:    public class SampleResource {   
5:        
6:      //You can Refrence existing osgi service   
7:      //@Reference   
8:      //private MyService service;   
9:        
10:      @GET   
11:      @Path("/sayhi")   
12:      public String helloWorld() {   
13:        return "SampleResource says hi";   
14:      }     
15:       
16:      @GET      
17:      @Path("/getoperation")   
18:      @Produces({MediaType.TEXT_PLAIN})   
19:      public String getServiceOperation() {   
20:        String status = false;   
21:        //service.dosomething return   
22:        return status;   
23:      }   
24:    }  

Services are registered at /services path (configurable via osgi console) so the helloservice will be available at http://localhost:4502/services/helloservice/sayhi
Note: Tested on cq 6.0
References:
  1. Step by Step: How to bring JAX-RS and OSGi together « EclipseSource Blog
  2. hstaudacher/osgi-jax-rs-connector · GitHub

Wednesday 25 February 2015

AEM Event Handling and filtering

AEM provides multiple ways of handling events to cater to changes in the repository. Some of the approaches are :

  • JCR level with observation manager.
  • 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.

These are already covered in detail on this blog http://blogs.adobe.com/experiencedelivers/experience-management/event_handling_incq
I want to add example of Event Filtering which I had to figure out as there was no example available.

Event filtering via sling event handling:

One of the major problem faced in event handling is that handler gets called for all events irrespective of the path or resource for which you want to handle the change. e.g. if you are listening to "org/apache/sling/api/resource/Resource/*" (* handles ADDED/REMOVED/CHANGED) topics your handler gets called for all the events be it your application or framework raised event.
You have to manually check if the path property matches the one you are interested into. Sling event has a property "event.filter" using which you can handle only those events which matches specific path and resourceType.

A sample component declaration with filter is listed below

 @Component(enabled = true, immediate = true)  
 @Service(value = EventHandler.class)  
 @Properties({  
     @Property(name = EventConstants.EVENT_TOPIC, value = {"org/apache/sling/api/resource/Resource/*"}),  
     @Property(name = EventConstants.EVENT_FILTER,value = "(&(path=/content/myapp/*/menu/*)(resourceType=myapp/components/page/product))") })  
Here property EventConstants.EVENT_FILTER defines the filter using path and resourceType. Event Admin checks the path to match the one defined above and then calls the event handler.
* is the wild-card character and will match any sub paths below /content/myapp/ , "&" is AND operation saying filter also needs to match the resourceType to be fit for processing by event handler.

Eventhandler black listing:

Eventadmin has a time-out (defaults to 5 secs) defined for a event to be handled, any handler taking time beyond this gets blacklisted, to handle this one should use sling Jobs which allows handling task via JobProcessor implementation. So basically you call JobUtil.processJob(..) and allow the event to be processed in the process(Event event) method.
 sample code:  
 @Component(enabled = true, immediate = true,metatype=true)  
 @Service(value = EventHandler.class)  
 @Properties({  
     @Property(name = EventConstants.EVENT_TOPIC, value = {"org/apache/sling/api/resource/Resource/*"}),  
     @Property(name = EventConstants.EVENT_FILTER,value = "(&(path=/content/myapp/*/menu/*)(resourceType=myapp/components/page/product))") })       
 public class Test implements EventHandler, JobProcessor {  
   private static final Logger LOG = LoggerFactory.getLogger(Test.class);  
   @Override  
   public void handleEvent(Event event) {  
     LOG.info("Handled event");  
     JobUtil.processJob(event, this);  
   }  
   @Override  
   public boolean process(Event job) {  
     LOG.info("Do some complex logic here");  
     return true;  
   }  
 }  
Pros and cons of previously mentioned approaches:

ApproachProsCons
Observation manager Low level and provides everything that you may need to handle update/delete/removal of nodes
You need to take care of registering/unregistering your handler.
You write more lines of code.
Maintain always on admin session to repository
If not implemented well It can cause performance nightmare.
Sling event handler Concise and easy to implement. Chances of blacklisting (configurable via Event admin in osgi console).
Can cause performance issues.
You have to figure out what Event and properties are provided.
Work-flows Well documented.
Allows Configuration and start/stop via workflow console.
Best suited for tasks which require human intervention.
Learning curve.
You need to write more code and configurations.
Scheduled java classes Allows you to do things which are not supported through previous mentioned approaches.
If you know what you want to do and can bear time gap of event occurrence vs handling.
You have to make sure that you are not creating bottlenecks.

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