9 Replies Latest reply on May 17, 2018 8:36 AM by sherrylynnh18586495

    RequestResponseFactory and FakeRequest

    Linda Juffermans (LG) 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

        • 1. Re: RequestResponseFactory and FakeRequest
          smacdonald2008 Adobe Employee

          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);

          • 2. Re: RequestResponseFactory and FakeRequest
            Linda Juffermans (LG) Level 1

            There's Retrieve the HTML contents of a cq:Page  and RequestResponseFactory ("The Adobe AEM Quickstart and Web Application.") ...

             

            I'm not trying to get node information, I'm trying to retrieve content (HTML and client libraries).

            • 3. Re: RequestResponseFactory and FakeRequest
              smacdonald2008 Adobe Employee

              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.

              • 4. Re: RequestResponseFactory and FakeRequest
                smacdonald2008 Adobe Employee

                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 | Apache Sling

                 

                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)

                • 5. Re: RequestResponseFactory and FakeRequest
                  Linda Juffermans (LG) 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/e344a064804dc920f5f c7e79ec8687899387a7b3/AemResou…  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.

                  • 6. Re: RequestResponseFactory and FakeRequest
                    sherrylynnh18586495 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 | Apache Sling

                     

                    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.

                    • 7. Re: RequestResponseFactory and FakeRequest
                      Linda Juffermans (LG) Level 1

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

                      • 8. Re: RequestResponseFactory and FakeRequest
                        Jörg Hoh Adobe Employee

                        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 JIRA  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

                        • 9. Re: RequestResponseFactory and FakeRequest
                          sherrylynnh18586495 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.