May 3, 2020
Estimated Post Reading Time ~

Get the rendered HTML for an AEM resource, component or page

It's easy to retrieve a rendered component by making a GET request. Apache Sling's SlingMainServlet and DefaultGetServlet will process GET requests, take the path's extension into account, and return the rendered resource. The most obvious example of triggering this process is simply typing the component's path into the browser's address bar or making an AJAX call. You can retrieve the HTML markup (or JSON, XML, txt, PDF, etc...) for a component as well as a page if you provide the correct path. After all, they're both just Sling resources.

Trying to get the rendered HTML of a component on the server side is still easy, but requires a little more work. Without knowing the inner workings of Sling, you might use Java's java.net.HttpUrlConnection class to construct and make an HTTP request from within your application to your application.

The better way is to use the SlingRequestProcessor service as the entry point into Sling's process. The processRequest method of the SlingRequestProcessor takes an HttpServletRequest, HttpServletResponse, and Resource Resolver as parameters. The only trick is that you need to provide a request that enables you to set the request path and a response that enables you to get the OutputStream as a String.

AEM provides the RequestResponseFactory where you can easily get such a request and response.
AemResourceResolutionServlet.java
package com.nateyolles.aem;

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.servlets.SlingSafeMethodsServlet;
import org.apache.sling.engine.SlingRequestProcessor;

import com.day.cq.contentsync.handler.util.RequestResponseFactory;
import com.day.cq.wcm.api.WCMMode;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

@SlingServlet(paths={"/bin/foo"})
public class AemResourceResolutionServlet extends SlingSafeMethodsServlet {

/** Service to create HTTP Servlet requests and responses */
@Reference
private RequestResponseFactory requestResponseFactory;

/** Service to process requests through Sling */
@Reference
private SlingRequestProcessor requestProcessor;

@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {

/* The resource path to resolve. Use any selectors or extension. */
String requestPath = "/content/myapp/us/en/index/jcr:content/myparsys/mycomponent_f93d.html";

/* Setup request */
HttpServletRequest req = requestResponseFactory.createRequest("GET", requestPath);
WCMMode.DISABLED.toRequest(req);

/* Setup response */
ByteArrayOutputStream out = new ByteArrayOutputStream();
HttpServletResponse resp = requestResponseFactory.createResponse(out);

/* Process request through Sling */
requestProcessor.processRequest(req, resp, request.getResourceResolver());
String html = out.toString();
}
}


You'll need to provide your own mock request and response in Apache Sling. Fortunately, it already exists. You need the HttpRequest, HttpResponse, and TestServletOutputStream classes.
SlingResourceResolutionServlet.java
package com.nateyolles.sling;

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.servlets.SlingSafeMethodsServlet;
import org.apache.sling.engine.SlingRequestProcessor;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

@SlingServlet(paths={"/bin/foo"})
public class SlingResourceResolutionServlet extends SlingSafeMethodsServlet {

/** Service to process requests through Sling */
@Reference
private SlingRequestProcessor requestProcessor;

@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {

/* The resource path to resolve. Use any selectors or extension. */
String requestPath = "/content/myapp/us/en/index/jcr:content/myparsys/mycomponent_f93d.html";

/*
* Create a fake request and fake response. The response adds a method to make the HTML accessible.
* You need the following three files from Apache Sling:
*
* https://github.com/apache/sling/blob/trunk/testing/junit/scriptable/src/main/java/org/apache/sling/junit/scriptable/HttpRequest.java
* https://github.com/apache/sling/blob/trunk/testing/junit/scriptable/src/main/java/org/apache/sling/junit/scriptable/HttpResponse.java
* https://github.com/apache/sling/blob/trunk/testing/junit/scriptable/src/main/java/org/apache/sling/junit/scriptable/TestServletOutputStream.java
*/
final HttpRequest req = new HttpRequest(requestPath);
final HttpResponse resp = new HttpResponse();

/* Process request through Sling */
requestProcessor.processRequest(req, resp, request.getResourceResolver());
String html = resp.getContent();
}
}


You will need to include the org.apache.sling.engine dependency in your pom file. If your bundle resolves but your component remains unsatisfied, make sure sure you've included the package in the Import-Package section of your maven-bundle-plugin.


By aem4beginner

1 comment:

If you have any doubts or questions, please let us know.