4

It seems like Sling expects every form POST to modify the JCR. So the expected/standard behavior would be a POST-redirect-GET, which is fine for most things. However, I need to be able to POST to AEM and then use the data in that POST to create a rendered result. Our use of AEM is stateless and so I don't want to carry the POST'd data in Session in order to utilize it in a subsequent GET.

Some have recommended putting the POST'd data in Browser sessionStorage, but that doesn't have broad enough support to be sufficient.

As far as I can tell there is no way for Sling in AEM to take a POST and produce a rendered result.

Here is a screenshot of what a POST produces in the page/resourceType component and in any Sling included jsp's that happen to be involved in the rendering.

enter image description here

I have tried things like using the "nop" operation.

<input type="hidden" name=":operation" value="nop" />

But either way all servlets think a POST is happening and don't render properly.

There is the option of creating a custom servlet, to handle the POST, but then how do you render the templated output and change the request so that all the components think they are serving a GET?

UPDATED: Here is a screenshot of the "nop" POST.jsp result. enter image description here

jedatu
  • 4,053
  • 6
  • 48
  • 60
  • Do you need a custom response while creating nodes or for POST requests to existing nodes? – santiagozky Apr 23 '14 at 11:59
  • The POST does not modify or create nodes. It is a POST'd payload to existing nodes or servlet, because the payload is too big for a GET. The payload is not persisted to the JCR but is used to shape aspects of what is displayed. – jedatu Apr 23 '14 at 12:56

3 Answers3

2

What you can do is create a POST.jsp file in the appropiate resourceType.

If your POST request go to /content/yourapp/something, which has a resourceType: your/app/example. Then you can create a file /apps/your/app/example/POST.jsp with whatever render you wish. You can even include your default rendering script in the POST.jsp file if you need it to be rendered the same as the GET requests.

The other option is to use a servlet registered for POST requests and internally use the SlingRequestProcessor service. That service allow you to programmatically process a request through Sling. You can use a SlingRequestWrapper to wrap your request and override getMethod() to return "GET". That should process the request as if it was a GET request.

santiagozky
  • 2,519
  • 22
  • 31
  • This does not work, as far as I can tell. My POST.jsp page gets called, but all components on that page render the status method rather than the desired output. There's really no advantage to using the POST.jsp at that point. – jedatu Apr 23 '14 at 15:14
  • @jedatu good point, you would need to add a POST.jsp to every single component that you include in the page. probably not feasible – santiagozky Apr 24 '14 at 08:31
  • @jedatu the slingrequestprocessor maybe? I added an alternative to my answer – santiagozky Apr 24 '14 at 08:40
  • The SlingHttpServletRequestWrapper does seem to be the key. I overwrote the getMethod() to return "GET" and then called slingRequest.getRequestDispatcher(resource.getParent().getPath()+".html").forward(wrapper, response); – jedatu Apr 24 '14 at 18:27
2

This sounds like a somewhat funky use case, IIUC you are using a large request parameter P to drive the rendering?

Using a custom POST servlet should work, if you use something like slingRequest.getRequestDispatcher(resource).forward(request, response) where request is a wrapper around the actual request, where request.getMethod() returns GET. You can then store your P data in request attributes.

The SlingHttpServletRequestWrapper class can be used to create such wrappers.

Bertrand Delacretaz
  • 6,100
  • 19
  • 24
1

Creating a custom servlet to handle a post could be an idea. After successfull write you could redirect to the modified resource - simple 302.

The other solution that comes to my mind is a custom Filter that would do the same. However, since AEM expects to get 200 instead of 302, it would be good to tell by atrribute or parameter that this POST needs to be redirected. Otherwise some of the AEM UI functionalities could brake. This is a quick example of an idea. You would probably need to write something more sophisticated.

@Component(immediate = true)
@Service
@Properties({
    @Property(name = Constants.SERVICE_DESCRIPTION, value = "Desc"),
    @Property(name = Constants.SERVICE_VENDOR, value = "Company name"),
    @Property(name = Constants.SERVICE_RANKING, intValue = RedirectFilter.RANKING),
    @Property(name = "filter.scope", value = "request") })
public class RedirectFilter implements Filter {

public static final int RANKING = -1000; // low ranking

@Override
public void init(final FilterConfig filterConfig) throws ServletException {
}

@Override
public void destroy() {
}

@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
        throws IOException, ServletException {
    if (request.getParameter("redirect").equals("true")) {
        ((SlingHttpServletResponse) response).sendRedirect(((SlingHttpServletRequest)request).getRequestURI());
    }
}

}

Michal Chudy
  • 1,883
  • 2
  • 21
  • 41
  • Does the redirect happen server-side? The POST-redirect-GET model will not work in this case because the payload will be lost in the redirect. – jedatu Apr 23 '14 at 12:52
  • No, it is browser-side. I did not get that you actually do not want to save data. JSP internal forward may be the way, but you would have to check it. I'll check it when I have a moment. – Michal Chudy Apr 23 '14 at 18:38