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:
- 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.
- 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.
- 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
Another good reason to use resourceType is that the Sling Engine will take care of permissions for you. Users who cannot access a particular resource will not be able to invoke the servlet.
LikeLike
Yes that’s true . Thanks for mentioning here.
Regards
Hashim
LikeLike
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?
LikeLike
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
LikeLiked by 1 person
@1what is the resource path in doGET method if we use resourceType
LikeLike
Pingback: A Brief Summary of Servlets in Apache Sling | Terra Beata
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) {
}
}
LikeLike
Hi, Could you check whether /bin/ is included in your Apache Sling Servlet/Script Resolver and Error Handler configuration ? Is your bundle resolved ?
Have you tried using the resourceType instead of path ?
http://stackoverflow.com/questions/29102285/how-to-invoke-sling-servlet-that-uses-resourcetype-instead-of-paths-in-slin
LikeLike
I tried with “/libs/promotion” result is same.
LikeLike
When I check with /system/console/jcrresolver its not resolving servlet also, What will be url for GET if I use resourceTypes=”apps/trustX/components/includes/promotionFeed”.
LikeLike
There wont be any URL if you use resourceType. The servlet should hit whenever there is a component of promotionFeed Resource type on your page.
LikeLike
Got it, thanks I made it worked, was having issue with my POM.xml
LikeLike
Hi Hashim,
I am trying to use a Servlet to login an user based on the URL pattern and query param. Any idea how to achieve this?
Thanks
LikeLike
Hi Tuhin, You can make use of the servlet path : j_security_check to make a POST call with some parameters to get the login session . Read more : https://sling.apache.org/documentation/the-sling-engine/authentication/authentication-authenticationhandler/form-based-authenticationhandler.html
If you are not using AEM’s authentication handler , you can create a custom authentication handler to achieve this.
LikeLike
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?
LikeLike
Hi Tuhin, It depends which AEM you are using. Please read this link http://aemfaq.blogspot.com/2014/10/how-to-set-timeout-for-login-token.html for this configuration.
LikeLike
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
LikeLike
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.
LikeLike
Can you please explain difference between httpservlet and slingservlet? I am not getting clear picture about this.
LikeLike
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.
LikeLike
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
LikeLike
Yes you should allow the Servlet path in Dispatcher and Akamai . Also you have to provide that custom path in Apache Sling Servlet/Script Resolver and Error Handler Configuration.
LikeLike
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
LikeLike
Hi Bharat,
I am sorry for the confusion. As per Apache documentation : https://sling.apache.org/documentation/the-sling-engine/servlets.html ” If both are set, the servlet is registered using both ways.”
Thanks.
LikeLike
in OSGI if i want yo register a servlet by custom path like “/abc/data” instead of “/bin, /libs” where in OSGI config I have to do the changes.?
LikeLike
Hi Nikita,
I think it is “Apache Sling Servlet/Script Resolver and Error Handler” what you are referring to.
LikeLike
very useful info, and please keep updating……..
LikeLiked by 1 person
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
LikeLike
Hi Srikanth,
You’re welcome.
This is given just as a sample in the post . For a real world use-case you might have to choose a resourceType of your component/ page. If its same the best possible servlet match should be picked . You may verify that from http://localhost:4502/system/console/servletresolver?url=sling%2Fservlet%2Fdefault&method=POST
LikeLike
Hi if i have to write a servlet for an ajax call made from some client libs, can i write a servlet with resourceTypes. What will be the url for that servlet doGet ajax call
LikeLike
Hi Sreenath, Yes it should be possible, using selectors and resourceType. Take reference from this query. https://forums.adobe.com/thread/2333823
LikeLike
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
LikeLike
You can do so by passing the num1 and num2 as selectors and read like its done in this post – http://aemcorner.blogspot.com/2014/11/introduction-to-sling-servlets-in-aem.html
LikeLike
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.
LikeLike
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.
LikeLike
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
LikeLike
Hi Umesh,
This is as per the new OSGi declarative service definition. Check here https://medium.com/adobetech/using-the-osgi-declarative-service-in-aem-6-4-21102f649d54
As you are writing a Sling Servlet it is mandatory to create it with @Component annotation.
LikeLike