Sling Servlet in AEM
Writing a Sling Servlet in AEM is one of the basic building block to start working with AEM. Sling servlet are basically used when front end developers need to make ajax call and want to get response in form of json. There are two ways in which a developer can register a servlet using path or selector.
In this tutorial i will tell you which approach is better and what are the best practices to create sling servlet in AEM.
After completing this tutorial , you will have a clear understanding about:-
- How to write Sling Servlet using path in AEM.
- How to write Sling Servlet using a resource type and selector.
- Advantages of registering servlet using selector over path.
- Sling Servlet Best Practices
Pre-requisite:-
You have setup you eclipse and code base. If not go through this tutorial to Set up AEM Project in Eclipse.
Write Sling Servlet using path in AEM
Lets write a sling servlet that returns json data by registering using path. When you create a project using AEM plugin, it will create a sample servlet file for you under core–> servlet
- Open SimpleServlet.java file and paste below code, i will explain the code line by line.
/* * Copyright 2015 Adobe Systems Incorporated * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.training.aemcq5tutorials.core.servlets; import org.apache.felix.scr.annotations.Reference; 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.resource.Resource; import org.apache.sling.api.servlets.SlingAllMethodsServlet; import org.apache.sling.api.servlets.SlingSafeMethodsServlet; import org.apache.sling.commons.json.JSONException; import org.apache.sling.commons.json.JSONObject; import javax.jcr.Repository; import javax.servlet.ServletException; import java.io.IOException; /** * Servlet that writes some sample content into the response. It is mounted for * all resources of a specific Sling resource type. The * {@link SlingSafeMethodsServlet} shall be used for HTTP methods that are * idempotent. For write operations use the {@link SlingAllMethodsServlet}. */ @SuppressWarnings("serial") @SlingServlet(paths = "/bin/custom/path") public class SimpleServlet extends SlingSafeMethodsServlet { @Reference private Repository repository; @Override protected void doGet(final SlingHttpServletRequest req, final SlingHttpServletResponse resp) throws ServletException, IOException { resp.setContentType("application/json"); String keys[] = repository.getDescriptorKeys(); JSONObject jsonobject = new JSONObject(); for(int i=0;i<keys.length;i++){ try { jsonobject.put(keys[i], repository.getDescriptor(keys[i])); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } resp.getWriter().println(jsonobject.toString()); } }
- Here i am registering our simple servlet at path /bin/custom/path.
- Then i am setting the content type as json.
- Finally i am returning the response.
Ajax call that you can use to call this servlet using Rest API:-
$.ajax({ type : "GET", url : '/bin/custom/path', /*data : { pass your request parameter here, currently we are not passing any data },*/ success : function(data, textStatus, jqXHR) { //write your logic that you need to perform on sucess }, error : function(XMLHttpRequest, textStatus, errorThrown) { //write your logic that you need to perform on error } });Now go to your browser type http://localhost:4502/bin/custom/path and you can see you json, This url can be used by front end developers to get the json response and process it accordingly.
Write Sling Servlet using a resource type and selector
Lets write a sling servlet that returns json data by registering using resource type and selector.
- Again Open SimpleServlet.java file and paste below code, i will explain the code line by line.
/* * Copyright 2015 Adobe Systems Incorporated * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.training.aemcq5tutorials.core.servlets; import org.apache.felix.scr.annotations.Reference; 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.resource.Resource; import org.apache.sling.api.servlets.SlingAllMethodsServlet; import org.apache.sling.api.servlets.SlingSafeMethodsServlet; import org.apache.sling.commons.json.JSONException; import org.apache.sling.commons.json.JSONObject; import javax.jcr.Repository; import javax.servlet.ServletException; import java.io.IOException; /** * Servlet that writes some sample content into the response. It is mounted for * all resources of a specific Sling resource type. The * {@link SlingSafeMethodsServlet} shall be used for HTTP methods that are * idempotent. For write operations use the {@link SlingAllMethodsServlet}. */ @SuppressWarnings("serial") @SlingServlet(resourceTypes = "geometrixx/components/homepage", selectors = "data", extensions = "html", methods = "GET", metatype =true) public class SimpleServlet extends SlingSafeMethodsServlet { @Reference private Repository repository; @Override protected void doGet(final SlingHttpServletRequest req, final SlingHttpServletResponse resp) throws ServletException, IOException { resp.setContentType("application/json"); String keys[] = repository.getDescriptorKeys(); JSONObject jsonobject = new JSONObject(); for(int i=0;i<keys.length;i++){ try { jsonobject.put(keys[i], repository.getDescriptor(keys[i])); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } resp.getWriter().println(jsonobject.toString()); } }
- Here i am registering our simple servlet at resourceType geometrixx/components/homepage and selector data.
Ajax call that you can use to call this servlet using Rest API:-
$.ajax({ type : "GET", url : '/content/geometrixx/en.data.html, /*data : { pass your request parameter here, currently we are not passing any data },*/ success : function(data, textStatus, jqXHR) { //write your logic that you need to perform on sucess }, error : function(XMLHttpRequest, textStatus, errorThrown) { //write your logic that you need to perform on error } });Now go to your browser type http://localhost:4502/content/geometrixx/en.data.html and you can see you json, This url can be used by front end developers to get the json response and process it accordingly.
Advantages of registering servlet using selector over path:-
Adobe recommends using resourceType instead of using path because of following reasons:-
- When we register a servlet using path , we must be specific what all paths are allowed as If we define something randomly, our servlet might not be function properly. Only a limited set of paths are allowed and the rest are blocked. We can add more path using Apache Sling Servlet / Script Resolver and Error Handler. Allowing more paths to execute servlet make you application vulnerable. That’s why you should not open more doors for servlets to run until and unless it is required.
- You might also need to tell specific paths to your consumers , who are consuming servlet response using ajax and any change in that path could have a serious affect. This might not be the case when you use resourceType.
- Sling Engine will take care of permissions if you register servlet using Resource Type. Users who cannot access a particular resource will not be able to invoke the servlet.
Sling Servlet Best Practices:-
DO’S |
@SlingServlet( resourceTypes = "sling/servlet/default", selectors = "selector", extensions = "tab", methods = HttpConstants.METHOD_GET ) |
DONT |
@Component @Service(value = javax.servlet.Servlet.class) @Properties({ @Property(name = "sling.servlet.resourceTypes", value = { "sling/servlet/default" }), @Property(name = "sling.servlet.selectors", value = { "selector" }), @Property(name = "sling.servlet.extensions", value = { "tab" }), @Property(name = "sling.servlet.methods", value = { HttpConstants.METHOD_GET }) }) |
DO’S |
@SlingServlet( resourceTypes = "sling/servlet/default", selectors = "selector", extensions = "tab", methods = HttpConstants.METHOD_GET ) @Properties({ @Property(name = Constants.SERVICE_VENDOR, value = "Cognifide"), @Property(name = Constants.SERVICE_DESCRIPTION, value = "Some description") }) |
DONT |
@SlingServlet(methods = "GET") @Properties({ @Property(name = Constants.SERVICE_VENDOR, value = "Cognifide"), @Property(name = Constants.SERVICE_DESCRIPTION, value = "Some description"), @Property(name = "sling.servlet.selectors", value = "selector"), @Property(name = "sling.servlet.extensions", value = "tab"), @Property(name = "sling.servlet.resourceTypes", value = { "sling/servlet/default" }) }) |
DO’S |
@SlingServlet( resourceTypes = "sling/servlet/default", selectors = "selector", extensions = "tab", methods = HttpConstants.METHOD_GET ) |
DONT |
@Service @Component @SlingServlet( resourceTypes = "sling/servlet/default", selectors = "selector", extensions = "tab", methods = HttpConstants.METHOD_GET ) |
That’s all about working with Sling Servlet in AEM.
Leave a Reply