Servlets


What is a Servlet?

A servlet is a Java programming language class that is used to extend the capabilities of servers that host applications accessed by means of a request-response programming model. Although servlets can respond to any type of request, they are commonly used to extend the applications hosted by web servers.


In Sling, servlets can be registered as OSGi services by the below mentioned samples:

1. The @SlingServlet annotation

@SlingServlet(
resourceTypes = "sling/servlet/default",
selectors = "hello",
extensions = "html",
methods = "GET")
public class MyServlet extends SlingSafeMethodsServlet {

@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
//Write your logic here
}
}

 2. The @Properties and @Property annotations

@Component(metatype = true)
@Service(Servlet.class)
@Properties({
@Property(name = "sling.servlet.resourceTypes", value = "sling/servlet/default"),
@Property(name = "sling.servlet.selectors", value = "hello"),
@Property(name = "sling.servlet.extensions", value = "html"),
@Property(name = "sling.servlet.methods", value = "GET")
})
public class MyServlet extends SlingSafeMethodsServlet {

@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
/*Write your logic here.*/
}
}

Besides the above methods , you can register a Sling Servlet using the Standard approaches:

1. Registering the servlet by path

@SlingServlet(
paths={"/bin/customservlet/hashim"}
)
@Properties({
@Property(name="service.pid", value="com.day.servlets.SampleServlet",propertyPrivate=false),
@Property(name="service.description",value="SampleDescription", propertyPrivate=false),
@Property(name="service.vendor",value="SampleVendor", propertyPrivate=false)
})
public class SampleServlet extends SlingAllMethodsServlet
{
@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException
{
//Write your custom code here
}

@Override
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException
{
//Write your custom code here
}
}

2. Register servlet by Resource Type

@SlingServlet(
resourceTypes = {"rep:User"},
methods = {"GET", "POST"}
)
@Properties({
@Property(name="service.pid", value="com.day.servlets.SampleServlet",propertyPrivate=false),
@Property(name="service.description",value="SampleDescription", propertyPrivate=false),
@Property(name="service.vendor",value="SampleVendor", propertyPrivate=false)
})
public class SampleServlet extends SlingAllMethodsServlet
{
@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException
{
//Write your custom code here
}

@Override
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException
{
//Write your custom code here
}
}

 

Note:  If you need your @SlingServlet to fetch some properties from Felix Console Configurations using @Properties , add the parameter “metatype=true” in the form of declaration where @SlingServlet is used. This is the parameter responsible for a Service component to be available in Felix Console configMgr. 

 

However there is reason why resourceType is much more preferential and suggested for writing SlingServlets. Below are the few reasons I could think of:

  1. While defining a path , you must be specific what all paths are allowed to be used in the ServletResource OSGi service. If you define something randomly, your servlet might not be fucntional. Only a limited paths are allowed and the rest are blocked unless you open them up. This is resolved using resourceType.
  2. You may have also configure the dispatcher , if you use some random path for your servlet. This might be a potential security threat and a needless configuration.
  3. You might also have to specify the paths to your consumers for your servlet and any change in that path could have a serious affect. This might not be the case when you use resourceType

37 thoughts on “Servlets

  1. How granular should the resourceType be? If a servlet is intended to be consumed by only one component do we just hard code that in? What if it’s later extended? Will child components be able to access this if their sling:superType is the original resourceType?

    Like

    • Hi Don,
      If the servlet is intended to be consumed by only one component , you can directly mention that in the resourceType property. Or if has to be consumed by multiple components you can mention the resourceType property as an Array of Strings.
      If there is a provision of extension later, and you don’t want to change JAVA servlet code, go to “path” definition.

      For child components , as long as exact match of sling:resourceType is present , the servlet would execute , it wont be applicable for sling:superResourceType . The resourceType property will look for sling resolution mechanism. Read More https://sling.apache.org/documentation/the-sling-engine/servlets.html

      Regards
      Hashim

      Liked by 1 person

  2. Pingback: A Brief Summary of Servlets in Apache Sling | Terra Beata

  3. Hey Hashim,

    I am trying SlingServlet with paths as below in AEM 6.2, but it always gives me below issue, can you suggest:
    Resource at ‘/bin/promotion’ not found: No resource found,

    @SlingServlet(
    paths={“/bin/promotion”}
    )

    @Properties({
    @Property(name=”service.pid”, value=”com.nvidia.nvidiagdc.components.servlets.PromotionFeedServlet”,propertyPrivate=false),
    @Property(name=”service.description”,value=”Promoiton Feed”, propertyPrivate=false),
    @Property(name=”service.vendor”,value=”NVIDIA”, propertyPrivate=false)
    })

    public class PromotionFeedServlet extends SlingAllMethodsServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(final SlingHttpServletRequest request,
    final SlingHttpServletResponse response) {
    }
    }

    Like

      • So you are saying once I am inside my original servlet I need to make another call to j_security_check servlet with j_username and j_password as parameters. Correct?

        Could you please also tell me another thing, by default what is the time a user is logged in to aem after log in if using AEM’s authentication handler?

        Like

          • Hi Hashim,

            I am trying to login with the proposed way. The below is the code I have in my servlet.

            HttpClient httpClient = new HttpClient();
            PostMethod postMethod = new PostMethod(“http://localhost:4502/content/tuhin/home/j_security_check”);

            postMethod.addParameter(“j_username”, “tuhin”);
            postMethod.addParameter(“j_password”, “tuhin”);
            postMethod.addParameter(“_charset_”, “UTF-8”);

            httpClient.executeMethod(postMethod);

            Now this code is returning 302 status code. I can see its not logging in with the intended user.

            Am I doing something wrong?

            I also tried to follow a separate approach, with this one I am getting 403.

            String url = “http://localhost:4502/content/tuhin/home/j_security_check”;
            URL obj = new URL(url);
            HttpURLConnection con = (HttpURLConnection) obj.openConnection();

            con.setRequestMethod(“POST”);
            con.setRequestProperty(“User-Agent”, “Mozilla/5.0”);
            con.setRequestProperty(“Accept-Language”, “en-US,en;q=0.5”);
            con.setRequestProperty (“Authorization”, “Basic ” + Base64.encodeBase64(“tuhin:tuhin”.getBytes()));
            con.setDoOutput(true);
            con.setDoInput(true);
            con.connect();

            DataOutputStream wr = new DataOutputStream(con.getOutputStream());
            wr.flush();
            wr.close();

            int responseCode = con.getResponseCode();
            System.out.println(“\nSending ‘POST’ request to URL : ” + url);
            System.out.println(“Response Code : ” + responseCode);

            Please share your thoughts on the same.

            Thanks and Regards,
            Tuhin

            Like

            • Hi Tuhin, You need to observe the existing Login call to j_security_check. Try to login in AEM and check the parameters being passed there . There is an extra Form paramter j_validate=”true”

              Also some extra parameters are defined in /libs/granite/core/components/login/login.jsp

              Try to make your post call as close as the existing Login call to make it work.

              Like

    • A normal httpservlet is the basic version of servlet for java with limited features, while Sling Servlet can be registered as a Service and can leverage features of Sling. Its more advanced version of Servlet and hence preferred in AEM.

      Like

  4. Hi,

    I just built a servlet and provided the path as /abcservices/abcIndex. Do I need to add this path to the dispatcher and Akamai as well? I am sorry to digress away from the topic.

    Regards,
    Sagar

    Like

  5. Hi Hashim

    You are saying that “The property resourceTypes is ignored if the sling.servlet.paths property is set’. But when I am writing the below code.

    @SlingServlet(
    resourceTypes = {“services/powerproxy”},
    selectors = {“groups”},
    methods = {“GET”, “POST”}
    )
    @Properties({
    @Property(name=”sling.servlet.paths”,value=”/bin/customservlet/hashim”, propertyPrivate=false)

    It is running in both the cases. i.e. via:
    1) http://localhost:4506/content/submitPage.groups.html
    2) http://localhost:4506/bin/customservlet/hashim

    Both the url are giving the result and “property resourceTypes” is not getting ignored.
    Can you please explain.

    Thanks
    Bharat

    Like

  6. Hi Hashim,

    Thanks for maintaining this very good article, it’s very useful. Can you please answer my below question.

    Can I register MyServlet (POST) using resourceType as default servlet like below. Is this the correct way of registering a resourceType sling servlet? or will it override any default sling functionality?

    @SlingServlet(
    resourceTypes = “sling/servlet/default”,
    selectors = “hello”,
    extensions = “html”,
    methods = “POST”)
    public class MyServlet extends SlingSafeMethodsServlet {

    Thanks,
    Srikanth

    Like

      • Hi
        i am trying to write a servlet that will add two number and i want to use selectors to give input
        package com.mycompany.myproject.janneon.core.servlets;

        import java.io.IOException;
        import java.io.PrintWriter;

        import org.apache.felix.scr.annotations.sling.SlingServlet;
        import org.apache.sling.api.SlingHttpServletRequest;
        import org.apache.sling.api.SlingHttpServletResponse;
        import org.apache.sling.api.servlets.SlingAllMethodsServlet;
        import org.apache.sling.commons.json.JSONException;
        import org.apache.sling.commons.json.JSONObject;

        @SlingServlet(name=”com.mycompany.myproject.janneon.core.servlets.AddingTwoNumbersServlet”,
        description=”Adding Two Numbers Servlet”,
        label = “Adding Two Numbers Servlet”,
        paths = “/bin/addingnumbers”
        )
        public class AddingTwoNumbersServlet extends SlingAllMethodsServlet {

        /**
        *
        */
        private static final long serialVersionUID = 1L;

        protected void doGet(SlingHttpServletRequest slingRequest, SlingHttpServletResponse slingResponse) {
        int sum;
        int x,y;
        String a = slingRequest.getParameter(“num1”);
        String b = slingRequest.getParameter(“num2”);
        x = Integer.parseInt(a);
        y = Integer.parseInt(b);
        sum = x + y;
        JSONObject jsonObj = new JSONObject();
        try {
        jsonObj.put (“x+y=”, sum);
        PrintWriter pw = slingResponse.getWriter();
        pw.println(jsonObj.toString());
        } catch (JSONException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }

        }

        }

        Output : http://localhost:4502/bin/addingnumbers/?num1=4&num2=10
        i am passing parameters, but i want use selectors to pass input

        Like

  7. Hi Hashim,
    Can we call sling servlet hosted on AEM server from some other system which is not hosted on AEM same as we call any rest service or we need to create a rest service for this using Java Rest API.

    Like

    • Hi,
      You might need to allow external URLs to have access to your dispatcher and then allow that path for anonymous access. this already works in AEM – try /content/geometrixx/en.json You should also allow CORS from your custom servlet.
      Create a JAVA REST is also another method and that would work too.

      Like

  8. Hi Hashim,
    I have a question regarding SlingServlet that is:
    Why it is mandatory to make a sling servlet an osgi service if I not make it service, it is showing 404 ?
    I am using aem 6.4 and using new style of annotation like
    @Component(service = Servlet.class, immediate = true, property = {
    Constants.SERVICE_DESCRIPTION + “=Querybuilder servlet”, “sling.servlet.paths=/bin/queryexample” })

    Thank You
    Umesh Thakur

    Like

Leave a comment