Friday, 4 March 2016

Debugging AEM 6.1 internals


There are times when you get an ugly error log with NPE or other exceptions coming from the internal AEM APIs and you are clueless about what could be wrong.
Well if you happen to have the jar of the related feature you can easily decompile the jar and take a look at what exactly might be causing the error or debug it.

Starting AEM 6.1 Adobe only releases uber-jar in the public repositories which contains only the signatures and empty method bodies to protect their intellectual property.
This can be very limiting to a developer as you can't understand the failures, However there is a workaround to fetch the jar directly from the deflated AEM directory.

Steps to get the Jar:

  1. Identify the OSGI bundle which contains the class by using dependency finder http://localhost:4502/system/console/depfinder e.g. if the exceptions are pointing to com.day.cq.mailer.impl.CqMailingService drop the impl part and search for the package "com.day.cq.mailer" which will result in exported by com.day.cq.cq-mailer (297). So the bundle you are looking for is "297".
  2. Now Go to <Install directory>\crx-quickstart\launchpad\felix directory here you will find all the bundles present/installed in AEM. open the directory "bundle297\version0.0" your jar will be inside this directory.

Now you can use your favorite decompiler to take a look into the code or add the jar to your project dependency and debug the required piece of code.

References: http://labs.6dglobal.com/blog/2015-09-16/decompile-aem-jar

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 = "(&amp;(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 = "(&amp;(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.

Friday, 19 December 2014

Watch your CQ Logs


There are times when you need to check cq server logs however you don't have access to the machine through vnc/putty, possible use cases could be QA/UAT environments where developers generally don't have machine rights. You will be left with option to asking for huge log files or viewing logs in browser via crxde console logs. Accessing logs this way could be very limiting as it won't show previous logs also it will show too many irrelevant logs which you may not be interested into.

There are few things that you can do to be able to view relevant logs via browser.

  • CQ provides CRXDELogServlet (com.day.crx.ide.CRXDELogServlet) which can be used with tail parameter to read limited number of lines. e.g. Hitting http://localhost:4502/bin/crxde/logs?tail=N will give last N lines of error log. This servlet is the one which reads error log and outputs retrieved lines to CRX console.
  • Add logger configuration to create different log file for your logger and then modify "Apache Sling Logging Configuration" to point to new log file. Say e.g. if your are only interested in logs of package com.example.util, create a logger configuration through osgi to log into separate logs/mylog.log file. Update "Apache Sling Logging Configuration" to point to logs/mylog.log. Now hitting http://localhost:4502/bin/crxde/logs?tail=N will read mylog.log file and display last N lines from it.






  • Write your own tool to read the log files. One of our clients needed functionality to have multiple log files and a way to allow admin users to view separate logs via browser. Though CRXDELogServlet provides basic log viewing capabilities it only allows a single log file configured in "Apache Sling Logging Configuration". We wrote another Servlet which can take log file name and lines to tail in request parameters and display lines from it. I will post code snippets in another post.


References:
http://sling.apache.org/documentation/legacy/logging.html