Search code examples
servletsosgiaemosgi-bundle

Adobe CQ (AEM) 6.3 Did Not Load Servlet


I had a jar from CQ 5.6 that expose several servlets. I moved the jar to new CQ 6.3 only to find out that the servlets are not ran (tested on Servlet Resolver and it answer with com.day.cq.commons.servlets.NonExistingDispatcherServlet -- equals to 404).

I have do several checklist to narrow down this issue:

  • The Jar is an OSGI bundle that have OSGI-INF metadata exposing its services - including the servlet. It is compiled under CQ 5.6 earlier.
  • The Bundle (jar) is properly registered and CQ shows the exposed servlets as service.
  • The Jar is installed under apps directory where it is included in Apache Sling Servlet/Script Resolver and Error Handler Execution Paths.

Is there any missing checklist to let the servlet handle the specific path defined in sling.servlet.paths property?

Sorry for the noob question. Thank you in advance.

EDIT Added the rough code -- i don't think you will be interested on what happens in doPost. As it is unrelated with registering servlet to AEM 6.3.

  package com.test.something;

  import java.util.Iterator;
  import java.io.*;

  import javax.jcr.*;
  import javax.servlet.ServletException;

  import java.util.*;
  import java.util.Date;
  import java.text.*;


  import org.apache.jackrabbit.api.security.user.Group;
  import org.apache.jackrabbit.api.security.user.User;
  import org.apache.jackrabbit.api.security.user.UserManager;
  import org.apache.jackrabbit.api.security.user.Authorizable;
  import org.apache.jackrabbit.api.*;

  import java.rmi.ServerException;
  import java.security.Principal;
  import org.apache.jackrabbit.api.security.principal.PrincipalManager;
  import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;

  import java.security.*;
  import javax.crypto.spec.SecretKeySpec;
  import javax.crypto.Mac;
  import org.apache.commons.codec.binary.*;

  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;

  import org.apache.felix.scr.annotations.Component;
  import org.apache.felix.scr.annotations.Properties;
  import org.apache.felix.scr.annotations.Property;
  import org.apache.felix.scr.annotations.Reference;
  import org.apache.felix.scr.annotations.Service;
  import org.apache.sling.api.SlingHttpServletRequest;
  import org.apache.sling.api.SlingHttpServletResponse;
  import org.apache.sling.api.servlets.SlingAllMethodsServlet;
  import org.apache.sling.jcr.api.SlingRepository;

  @Component(immediate = true)
  @Service
  @Properties({
   @Property(name = "sling.servlet.methods", value = "POST"),
   @Property(name = "sling.servlet.paths", value = { "/content/test" }),
   @Property(name = "service.description", value = "Test Servlet")
  })
  public class TestServlet extends SlingAllMethodsServlet {

     @Reference
     private SlingRepository repository;
     protected final Logger log = LoggerFactory.getLogger("SSOLogger");

     @Override
     protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
     throws ServerException, IOException {
        try {
         this.doPost(request, response);
        } catch (ServletException e) {
         //do some logging
        }
     }

     @Override
     protected void doPost(SlingHttpServletRequest request,
      SlingHttpServletResponse response)
     throws ServletException, IOException {
        try {
         //do something
        } catch (RepositoryException ex) {
         //do some logging
        }
     }
  }

And yes, this servlet is registered in OSGi Components. It states the properties correctly.

EDIT: Narrowing down the culprit it seems

@Reference
private SlingRepository repository;

does not seems to be loaded properly.. weird. It caused the component to be in Satisfied state instead of Active.

EDIT: Checking the OSGi Services in CQ, noticed that org.apache.sling.jcr.api.SlingRepository in CQ 5.6 was provided by com.day.crx.sling.server while in CQ 6.3 it is provided by com.adobe.granite.repository. Not sure if it is the cause or not.


Solution

  • After messing a bit and checking the logs. Apparently the issue lies on the maven scr plugin that did not generate the necessary binding (bind and unbind in @Reference) methods. Basically, i need to strictly define the method such as:

      public class TestServlet extends SlingAllMethodsServlet {
         @Reference(bind = "bindRepository", unbind = "unbindRepository")
         private SlingRepository repository;
    
         protected void bindRepository(SlingRepository repository){
            this.repository = repository;
         }
    
         protected void unbindRepository(SlingRepository repository){
            if(this.repository == repository){
               this.repository = null;
            }
         }
      }
    

    There are several item we need to check if the Service is stuck in Satisfied state:

    • Configuration, is every configuration field is configured?
    • Other services that it depends to, are they already active or also in Satisfied state?
    • Have you whitelisted the service ? -- if you are using slingRepository.loginAdministrative(null).
    • Any exception happen when it was activated (denoted by @Activate)?

    I know the checklist are incomplete, i am also still learning this OSGi thingy. It is interesting though a bit unclear (no documentation for dummies).