Post-Processing a Matched Sitemap Item with SiteMapItemHandlers
When the HST resolves a URL to an hst:sitemapitem, it will create a request dependent flyweight ResolvedSiteMapItem instance that wraps the immutable backing HST sitemap item. A developer can inject post-processing when some sitemap item has been resolved. During post-processing you can short-circuit the request, return a different ResolvedSitemapItem wrapping a different sitemap item (for example based on the document mapped to the sitemap item), set cookies on the response, set response headers, modify request attributes, etc. You can do that via the following recipe:
- Implement one or more custom HstSiteMapItemHandlers
- Configure the sitemap item handlers
- Configure on a sitemap item one or more sitemap item handlers
Implement a custom HstSiteMapItemHandler
When you want post-process a matched sitemapitem, you need to implement an HstSiteMapItemHandler. The most important method to implement is the process method, which looks as follows:
/** * @return a new or the original {@link ResolvedSiteMapItem}, or null * when the handler did for example already write the entire * response and request processing can be stopped * @throws HstSiteMapItemHandlerException */ ResolvedSiteMapItem process(ResolvedSiteMapItem resolvedSiteMapItem, HttpServletRequest request, HttpServletResponse response) throws HstSiteMapItemHandlerException;
The parameter resolvedSiteMapItem is the resolved sitemap item from the matched sitemap item or the returned one from the previous HstSiteMapItemHandler. A sitemap item can have a chain of multiple sitemap item handlers which all get their process method invoked as long as one does not return null. When the process method returns null, the request processing is short-circuited. Otherwise, a HstSiteMapItemHandler can return a different ResolvedSiteMapItem instance. This can be a completely different ResolvedSiteMapItem backed by a different hst:sitemapitem, or just a decorated version of the resolvedSiteMapItem. For example, the decorated version could return a different component for getHstComponentConfiguration().
An HstSiteMapItemHandler also gets a SiteMapItemHandlerConfiguration instance in init(ServletContext servletContext, SiteMapItemHandlerConfiguration handlerConfig). See below for the sitemap item handler's configuration.
Configure the sitemap item handlers
Below the project's hst:configuration node, there is a node called hst:sitemapitemhandlers. Below that node, you can configure your sitemap item handlers. The configuration consists of a node that can be of any name, of primary type hst:sitemapitemhandler. It has one mandatory property, hst:sitemapitemhandlerclassname, which is the fully qualified class name of your sitemap item handler class that implements HstSiteMapItemHandler. Furthermore, the hst:sitemapitemhandler can contain any string(s), boolean(s), long(s), double(s) or date(s) configuration properties, which in your sitemap item handler class all become available through init(ServletContext servletContext, SiteMapItemHandlerConfiguration handlerConfig).
The CND of the hst:sitemapitemhandler is as follows:
[hst:sitemapitemhandler] > nt:base, mix:referenceable - hst:sitemapitemhandlerclassname (string) mandatory - * (string) - * (string) multiple - * (boolean) - * (boolean) multiple - * (long) - * (long) multiple - * (double) - * (double) multiple - * (date) - * (date) multiple
Configure one or more sitemap item handlers on a sitemap item
Once you have configured your hst:sitemapitemhandler below the hst:sitemapitemhandlers node, and you have implemented your HstSiteMapItemHandler, you can invoke one or more sitemap item handler per matched sitemap item . This is done through the multivalued property hst:sitemapitemhandlerids on an hst:sitemapitem. A handler id is the node name of the hst:sitemapitemhandler node. If you configure multiple handlers in hst:sitemapitemhandlerids, their process methods will be invoked in the same order as they are stored in the hst:sitemapitemhandlerids property.
For example, if you have the following sitemap item handlers defined:
/hst:sitemapitemhandlers: /set-pragma-no-cache-handler: hst:sitemapitemhandlerclassname: ........... /redirect-if-logged-in-handler: hst:sitemapitemhandlerclassname: ...........
then you could have a sitemap item that uses the handler post-processing as follows:
/hst:sitemap: /bar: jcr:primaryType: hst:sitemapitem /foo: jcr:primaryType: hst:sitemapitem hst:sitemapitemhandlerids = [set-pragma-no-cache-handler, redirect-if-logged-in-handler]
The sitemap item foo will now invoke post matching processing handlers set-pragma-no-cache-handler and redirect-if-logged-in-handler.
HstSiteMapItemHandler invoking FilterChain to delegate request to other Servlet application
a HstSiteMapItemHandler can invoke javax.servlet.FilterChain directly with returning null in its process() method in order to delegate the request to another Servlet application.
HstFilter may invoke a configured HstSiteMapItemHandler for a specific sitemap item. If the HstSiteMapItemHandler implementation finally invokes FilterChain.doFilter() and returns null in its process() method, then HstFilter would not process the request any more, but the request will be delegated to another Servlet application due to the javax.servlet.FilterChain.doFilter() call.
If you want to use this advanced feature, then the HstSiteMapItemHandler class should extend org.hippoecm.hst.core.sitemapitemhandler.AbstractFilterChainAwareHstSiteMapItemHandler instead of implementing org.hippoecm.hst.core.sitemapitemhandler.HstSiteMapItemHandler interface and implement the following operation:
/** * Does custom request processing. * <P> * This method can return the original resolvedSiteMapItem or a new resolved sitemap item to serve * a different one. Or it can return null when it completes the custom request processing by itself * so HstFilter needs to stop the request processing. * </P> * <P> * This method also receives {@link FilterChain} instance so it can short circuit HST request * processing and continue processing next * {@link javax.servlet.Filter}s by invoking filterChain.doFilter(..). If you invoke * filterChain.doFilter(..) you <strong>must</strong> return <code>null</code> from * {@link #process(ResolvedSiteMapItem, HttpServletRequest, HttpServletResponse, FilterChain)} * because the HST rendering <strong>must</strong> be short-circuited * </P> * * @param resolvedSiteMapItem * @param request * @param response * @param filterChain * @return a new or the original {@link ResolvedSiteMapItem}, or <code>null</code> when the handler did for * example already write the entire <code>response</code> and request processing can be stopped * @throws HstSiteMapItemHandlerException */ ResolvedSiteMapItem process(ResolvedSiteMapItem resolvedSiteMapItem, HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws HstSiteMapItemHandlerException;