Dispatching requests in Sling Applications
Sling is built upon the Component API which has componentizing the page rendering as one of its corner stones. Therefore including the result of handling, rendering that is, a Content object is a central issue in Sling. To this avail the following methods are provided by the Component API:
ComponentRequest.getRequestDispatcher(Content)
Allows the inclusion of rendering of the given Content object.
ComponentRequest.getRequestDispatcher(String)
Allows the inclusion of rendering a Content object or, if no such object exists, delegation to the whatever container Sling is running in. In the case of Sling this is of course the delegation to the Servlet Container.
ComponentContext.getRequestDispatcher(Content)
Allows the inclusion of rendering of the given Content object.
ComponentContext.getRequestDispatcher(String)
Allows the inclusion of rendering a Content object or, if no such object exists,
delegation to the whatever container Sling is running in. In the case of Sling this is of course the delegation to the Servlet Container.
Note, that the methods in the ComponentRequest and in the ComponentContext are exactly the same. The reason to have them in both places is actually alignement with the Servlet API specification which has also respective methods in both places.
Examples
Example 1 - Including content with an object
Content someContent = request.getContent("/abs/path/to/content");
ComponentRequestDispatcher crd = request.getRequestDispatcher(someContent);
crd.include(request, response);
This example first acquires the Content object from the request, gets the request dispatcher to render the content and finally includes this rendering.
Example 2 - Including content with a path
ComponentRequestDispatcher crd = request.getRequestDispatcher("/abs/path/to/content");
crd.include(request, response);
This second example is equivalent to the first except, that acquiring the Content object is delegated to the request dispatcher and delayed until the output is actually requested for inclusion. Of course, if there is no Content object at the given path, this example will fall back to getting a dispatcher from the servlet container and dispatch to the resource /abs/path/to/content through the servlet container.
Dispatching also works with a relative path, like this:
ComponentRequestDispatcher crd = request.getRequestDispatcher("jcr:content");
crd.include(request, response);
If no child content of the Content of the request is available, the request dispatcher will try to include a servlet container resource whose path is relative to the current request.
JSP Request Dispatching
For scripted components handled by JSP, request dispatching works using either the Servlet API (e.g. ServletRequest.getRequestDispatcher(String)) or by using the <jsp:include> tag. In the JSP integration provided by the Sling Core Scripting, the request dispatcher returned will actually use a ComponentRequestDispatcher retrieved from the current request using the path given.
As a result, JSPs may include servlet container resources for rendering but also benefit from content mapping. For example, by using
<jsp:include path="jcr:content" />
the output of rendering the jcr:content child content of the request's content may easily be included in JSPs.
Note: The preferred way is of course to use the <sling:include> tag.
Issues with Request Dispatching
The following is a short list of current limitations of request dispatching:
- The current implementation just takes the path used to acquire the request dispatcher as is and tries to load the
Contentobject. There is no support to resolve in a way as the URL Mapper does. - Passing additional request parameters, providing a different request extension or a custom selector list is not currently supported by the
ComponentRequestDispatcher. It is foreseen to provide such functionality with additional API on theComponentRequestDispatcherinterface which may be called after acquiring the object but before calling theincludemethod. - Request forwarding as per
javax.servlet.RequestDispatcher.forwardis not currently supported. As a workaround, a simple redirection (with all its consequences) may be used.