Expand my Community achievements bar.

RequestResponseFactory and FakeRequest

Avatar

Level 1

Hi,

We use the RequestResponseFactory to retrieve content from AEM inside an OSGi bundle:

The service is obtained through:

@Reference

private RequestResponseFactory requestResponseFactory;

And used like this:

final HttpServletRequest servletRequest = requestResponseFactory.createRequest("GET", path);

WCMMode.DISABLED.toRequest(servletRequest);

final ByteArrayOutputStream responseOutputStream = new ByteArrayOutputStream();

final HttpServletResponse servletResponse = requestResponseFactory.createResponse(responseOutputStream);

servletResponse.getWriter().flush();

byte[] content = responseOutputStream.toByteArray();

Most methods of the FakeRequest class return null; e.g. getHeader, getServerName.

FakeRequest seems to cause errors that normal requests don't, e.g.:

15.03.2018 11:22:30.322 *ERROR* [pool-5-thread-2] com.day.cq.wcm.tags.IncludeTag Error while executing script view.jsp

org.apache.sling.api.scripting.ScriptEvaluationException:

  at org.apache.sling.scripting.core.impl.DefaultSlingScript.call(DefaultSlingScript.java:388)

  at org.apache.sling.scripting.core.impl.DefaultSlingScript.eval(DefaultSlingScript.java:171)

  at org.apache.sling.scripting.core.impl.DefaultSlingScript.service(DefaultSlingScript.java:463)

  at com.day.cq.wcm.tags.IncludeTag.includeScript(IncludeTag.java:176)

  ...

Caused by: java.lang.UnsupportedOperationException: null

  at com.day.cq.contentsync.impl.handler.util.FakeRequest$FakeHttpSession.getAttribute(FakeRequest.java:64)

  at org.apache.sling.scripting.jsp.jasper.runtime.PageContextImpl.doFindAttribute(PageContextImpl.java:470)

  at org.apache.sling.scripting.jsp.jasper.runtime.PageContextImpl.findAttribute(PageContextImpl.java:455)

  at org.apache.jsp.apps.lgi_002dforms.components.forms.honeypot.honeypot_jsp._jspService(honeypot_jsp.java:122)

where honeypot_jsp.java:122 is:

currentNode = (javax.jcr.Node) _jspx_page_context.findAttribute("currentNode");

which is compiled from this line in the JSP:

<cq:defineObjects />

We use the RequestResponseFactory with the SlingRequestProcessor for ContentSync handler and a customer service that uploads pages to an FTP server. Should we use RequestResponseFactory for these or is there a better method? How can we work around the issues described above?

Linda

9 Replies

Avatar

Level 10

Can you point to the URL where you found this information. We can see if we can reproduce your issue.

Typically to get node information from the AEM JCR - you use code like this with a system user.

Map<String, Object> param = new HashMap<String, Object>();

param.put(ResourceResolverFactory.SUBSERVICE, "datawrite");

ResourceResolver resolver = null;


try {

          

    //Invoke the adaptTo method to create a Session used to create a QueryManager

  resolver = resolverFactory.getServiceResourceResolver(param);

    session = resolver.adaptTo(Session.class);

Avatar

Level 10

Interesting - we do not have any HELPX examples on this use case. Let me try and find a better example than the one referencd in the URL. However - this provided a lot more detail on what you are trying to do.

Avatar

Level 10

Here is a much better example of how to perform this use case. Nate is an internal Adobe Community member: Get the rendered HTML for an AEM resource, component or page - Adobe Experience Manager | AEM/CQ | A...

Of course, you can always use a Java URL object to read the HTML of a Page too -- Reading Directly from a URL (The Java™ Tutorials > Custom Networking > Working with URLs)

Avatar

Level 1

I noticed I forgot to paste 1 line of code in my question (this would be line #5):

slingRequestProcessor.processRequest(servletRequest, servletResponse, resourceResolver);

I tried the code from https://gist.githubusercontent.com/nateyolles/1dc9f8699fce70916764/raw/e344a064804dc920f5fc7e79ec868...  but calling that servlet (on /bin/foo) causes the same error:

Caused by: java.lang.UnsupportedOperationException: null

at com.day.cq.contentsync.impl.handler.util.FakeRequest$FakeHttpSession.getAttribute(FakeRequest.java:64)

at org.apache.sling.scripting.jsp.jasper.runtime.PageContextImpl.doFindAttribute(PageContextImpl.java:470)

at org.apache.sling.scripting.jsp.jasper.runtime.PageContextImpl.findAttribute(PageContextImpl.java:455)

at org.apache.jsp.apps.lgi_002dforms.components.forms.honeypot.honeypot_jsp._jspService(honeypot_jsp.java:122)

at org.apache.sling.scripting.jsp.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)

at org.apache.sling.scripting.jsp.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:502)

... 560 common frames omitted

I still suspect this is due to the FakeRequest object lacking certain implementations of the HttpServletRequest; tho I don't have the source for FakeRequest.java so I can't tell what's on line 64.

I may resort to doing an HTTP request for the page (on publisher:4503/content/path/to/page) tho the SlingRequestProcessor seems cleaner (if it works) and wouldn't add the overhead of an HTTP request.

Avatar

Level 1

I too am encountering this problem for a specific instance of 6.3 but the line number is a little different:

Caused by: java.lang.UnsupportedOperationException: null

at com.day.cq.contentsync.impl.handler.util.FakeRequest$FakeHttpSession.getAttribute(FakeRequest.java:68)

at org.apache.sling.scripting.jsp.jasper.runtime.PageContextImpl.doFindAttribute(PageContextImpl.java:470)

at org.apache.sling.scripting.jsp.jasper.runtime.PageContextImpl.findAttribute(PageContextImpl.java:455)

at org.apache.jsp.apps.intel.dm.components.pages.data.head_jsp._jspService(head_jsp.java:121)

at org.apache.sling.scripting.jsp.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)

at org.apache.sling.scripting.jsp.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:502)

We take a copy of the rendered HTML and send it to our API that then analyses it.

Did you overcome the issue? Our OSGi component follows the same pattern as the aforementioned blog post:

Get the rendered HTML for an AEM resource, component or page - Adobe Experience Manager | AEM/CQ | A...

Could this be something to do with session use as per Tip 1 found here:

Three AEM / DPS Tips - Blog - 6D Global

However the JSPs do not use "in page" sessions but session are being used.

Avatar

Level 1

I did not overcome the issue; for pages we're using an HTTP request in stead of the requestResponseFactory solution.

Avatar

Employee Advisor

I ran about this issue some time ago: Sling - Users - Fake request/response classes

As follow up [SLING-5428] Move MockSlingHttpServletRequest+Response to org.apache.sling.servlet-helpers - ASF JIR...  has been created and it should be available in a separate bundle you can deploy to your instance (not sure if it's provided ootb in AEM in the meanwhile).

Jörg

Avatar

Level 1

Thanks Jorg and Linda for you replies.

Linda, I've tried the URL approach but find I get a 401

Jorg,

So I've tried to use Apache Sling :: Sling Servlet Helpers ​but don't appear to be able to get at the content... I can't be using the servlet helpers correctly?

I added the dependency to my pom as follows:

<dependency>
  <groupId>org.apache.sling</groupId>
  <artifactId>org.apache.sling.servlet-helpers</artifactId>
  <version>1.1.2</version>
</dependency>

and replaced response and request with mock versions as you'll see below (I've commented them out). I had to move things around because MockSlingHttpServletRequest requires a ResourceResolver.

@SlingServlet(

  paths={"/services/foo/bar"},

  methods = "GET"

)

@Slf4j

public class MyAnalysisServlet extends SlingSafeMethodsServlet {

  private static final long serialVersionUID = 1L;

  private static final String HEADER_REFERRER = "referer";

  private static final String EDITOR_PATH_PREFIX = "/editor.html";

  @Reference

  private transient RequestResponseFactory requestResponseFactory;

  @Reference

  private transient ResourceResolverFactory resourceResolverFactory;

  @Reference

  private transient SlingRequestProcessor requestProcessor;

  @Override

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

    final String referrer = request.getHeader(HEADER_REFERRER);

    handleRequest(request, response, referrer);

  }

private void handleRequest(SlingHttpServletRequest request, SlingHttpServletResponse response, final String referrer) throws ServletException, IOException {

  final String content = loadContent(referrer);

  try {

    sendResultResponse(request, response, referrer, content);

  } catch (ExecutionException e) {

    sendErrorOrThrow(response, e);

  }

}

private String loadContent(String referrer) throws ServletException, IOException {

  String contentPath = getContentPath(referrer);

  final HttpServletRequest request = requestResponseFactory.createRequest("GET", contentPath);

  WCMMode.PREVIEW.toRequest(request);

  final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

  final HttpServletResponse response = requestResponseFactory.createResponse(outputStream);

// final MockSlingHttpServletResponse response = new MockSlingHttpServletResponse();

  ResourceResolver resourceResolver = null;

  try {

    // ** the bundle is whitelisted as getAdministrativeResourceResolver(null) is deprecated **

    resourceResolver = resourceResolverFactory.getAdministrativeResourceResolver(null);

//  MockSlingHttpServletRequest request = new MockSlingHttpServletRequest(resourceResolver);

//  WCMMode.PREVIEW.toRequest(request);

    

     requestProcessor.processRequest(request, response, resourceResolver);

  } catch (LoginException e) {

     throw new ServletException("Error obtaining administrative resource resolver", e);

  } finally {

    if (resourceResolver != null) {

      resourceResolver.close();

    }

  }

  final String content = outputStream.toString(Charsets.UTF_8.name());

  // strip HTML comments

  return content.replaceAll("(?s)<!--.*?-->", "<!-- [Stripped comment placeholder] -->");

}

  private String getContentPath(String referrer) throws MalformedURLException {

    return //does stuff to the path;

  }

  private void sendResultResponse(SlingHttpServletRequest request, final SlingHttpServletResponse response, final String url, final String content) {

    // does stuff

  }

  private void sendErrorOrThrow(SlingHttpServletResponse response, ExecutionException e) throws IOException, ServletException {

    // does stuff

  }

}

Any ideas/pointers?

Many thanks for you time.