Problem Statement:
How can I invoke the Sling servlet from the OSGI service or from Sling Model?
Introduction:
We are aware of invoking a service by using @Reference @OSGiService if are referring to any other sling model inside the Sling servlet you can also use adaptTo({class-name}.class) to invoke a sling model within a servlet. But is there any way we can invoke servlet from the Sling model? Or OSGi service?
Yes, we can use the Sling Servlet Helpers bundle provides mock implementations of the SlingHttpServletRequest, SlingHttpServletResponse and related classes, along with fluent SlingInternalRequest and ServletInternalRequest helpers for internal requests.
The mock request/response implementations are meant to be used in tests and also with services like the SlingRequestProcessor when making requests to that service outside of an HTTP request processing context.
They are used under the hood by the SlingInternalRequest and ServletInternalRequest helpers to provide a simple and foolproof way of executing internal Sling requests.
The internal request helpers use either a SlingRequestProcessor
to execute internal requests using the full Sling request processing pipeline, or a ServletResolver
to resolve and call a Servlet or Script directly. The necessary “mocking” of requests are responses that happen under the hood which leads to much simpler code.
The latter direct-to-servlet (or script) mode is more efficient but less faithful to the way HTTP requests are processed, as it bypasses all Servlet Filters, in particular.
Step 1: Add the following Dependency to your core POM.XML
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.servlet-helpers</artifactId>
<version>1.4.6</version>
</dependency>
The org.apache.sling.servlet-helpers has dependency on the older version of the org.apache.sling.api version. However, you can request AMS to install the bundle manually on Felix console if your Maven build fails
Step 2: Create a simple Servlet as shown below:
package com.chatgpt.core.servlets;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.servlets.post.JSONResponse;
import org.osgi.service.component.annotations.Component;
import com.adobe.granite.rest.Constants;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
@Component(service = { Servlet.class }, property = { "sling.servlet.paths=" + SamplePathServlet.RESOURCE_PATH,
"sling.servlet.methods=POST" })
public class SamplePathServlet extends SlingAllMethodsServlet {
private static final long serialVersionUID = 1L;
public static final String RESOURCE_PATH = "/bin/sampleServletPath";
@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
throws ServletException, IOException {
response.setContentType(JSONResponse.RESPONSE_CONTENT_TYPE);
response.setCharacterEncoding(Constants.DEFAULT_CHARSET);
JsonObject jsonResponse = new JsonObject();
jsonResponse.addProperty("mesasge", "I am in Path based Servlet ");
try (PrintWriter out = response.getWriter()) {
out.print(new Gson().toJson(jsonResponse));
}
}
}
Step 3: Create a Sling model as shown below.
As you can see it internally uses SlingRequestProcessor API to mock internal request
package com.chatgpt.core.models;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.engine.SlingRequestProcessor;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.apache.sling.servlethelpers.internalrequests.SlingInternalRequest;
import org.apache.sling.servlets.post.JSONResponse;
import javax.annotation.PostConstruct;
import java.io.IOException;
@Model(adaptables = SlingHttpServletRequest.class)
public class ExampleModel {
@OSGiService
private SlingRequestProcessor slingProcessor;
@SlingObject
private ResourceResolver resourceResolver;
@OSGiService
private SlingRequestProcessor slingRequestProcessor;
@PostConstruct
private void init() {
try {
String responString = new SlingInternalRequest(resourceResolver, slingRequestProcessor, "/bin/sampleServletPath")
.withRequestMethod("GET")
.execute()
.checkStatus(200)
.checkResponseContentType(JSONResponse.RESPONSE_CONTENT_TYPE+";charset=UTF-8")
.getResponseAsString();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Step 4: Create an OSGi service as shown below:
package com.chatgpt.core.services.impl;
import java.io.IOException;
import com.chatgpt.core.services.InternalRequestService;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.engine.SlingRequestProcessor;
import org.apache.sling.servlethelpers.internalrequests.SlingInternalRequest;
import org.apache.sling.servlets.post.JSONResponse;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component(service = InternalRequestService.class, immediate = true, name = "Sample Internal Request service")
public class InternalRequestServiceImpl implements InternalRequestService {
@Reference
private SlingRequestProcessor slingRequestProcessor;
@Override
public String getInternalPathBasedRespone(ResourceResolver resourceResolver) {
try {
return new SlingInternalRequest(resourceResolver, slingRequestProcessor, "/bin/sampleServletPath")
.withRequestMethod("GET")
.execute()
.checkStatus(200)
.checkResponseContentType(JSONResponse.RESPONSE_CONTENT_TYPE+";charset=UTF-8")
.getResponseAsString();
} catch (IOException e) {
log.error("An error occurred while proccessing the request {} ", e.getMessage());
}
return StringUtils.EMPTY;
}
}