Using SiteMesh with RequestDispatcher's forward()
Asked Answered
T

1

5

I'm attempting to integrate SiteMesh into a legacy application using Tomcat 5 as my a container. I have a main.jsp that I'm decorating with a simple decorator.

In decorators.xml, I've just got one decorator defined:

<decorators defaultdir="/decorators">
  <decorator name="layout-main" page="layout-main.jsp">
    <pattern>/jsp/main.jsp</pattern>
  </decorator>
</decorators>

This decorator works if I manually go to http://example.com/my-webapp/jsp/main.jsp. However, there are a few places where a servlet, instead of doing a redirect to a jsp, does a forward:

getServletContext().getRequestDispatcher("/jsp/main.jsp").forward(request, response);

This means that the URL remains at something like http://example.com/my-webapp/servlet/MyServlet instead of the jsp file and is therefore not being decorated, I presume since it doesn't match the pattern in decorators.xml.

I can't do a <pattern>/*</pattern> because there are other jsps that do not need to be decorated by layout-main.jsp. I can't do a <pattern>/servlet/MyServlet*</pattern> because MyServlet may forward to main.jsp sometimes and perhaps error.jsp at other times.

Is there a way to work around this without expansive changes to how the servlets work? Since it's a legacy app I don't have as much freedom to change things, so I'm hoping for something configuration-wise that will fix this.

SiteMesh's documentation really isn't that great. I've been working mostly off the example application that comes with the distribution. I really like SiteMesh, and am hoping I can get it to work in this case.

Teasel answered 6/3, 2009 at 17:28 Comment(0)
E
9

My understanding is that SiteMesh is integrated into the application as a Servlet filter. By default, servlet filters are only invoked against the original incoming request (in your case, the request to the servlet). Subsequent forward or include requests are not passed throuh the filter, and therefore will not be passed through sitemesh.

You can, however, instruct the filter to be invoked on forwards, using something like this:

<filter-mapping>
    <filter-name>sitemesh</filter-name>
    <servlet-name>MyServlet</servlet-name>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

Which instructs the container to only operate on FORWARD requests. The other options are INCLUDE and REQUEST, you can have several elements.

So your options are to either change your filter config to specify FORWARD, or to change your filter-mapping to match the servlet path, rather than the JSP path. Either one should work.

Enrage answered 12/6, 2009 at 13:18 Comment(4)
This worked, applying the filter to the forwarded request and thus applying the sitemesh decorator to the forwarded jsp page. Thanks!Teasel
I'd seen those new directives but not yet had a need for them. Great advice.Holsinger
It's not working for me if I put both FORWARD and REQUEST as dispatcher scopes in the filter-mapping for me. FORWARD only works (but obviously breaks everything else), but otherwise it appears the initial incoming request before the FORWARD is stopping the FORWARD from processing. I've tried excluding the initial request in decorators.xml but that disables the entire request and forward... Gah!Emotionality
I've hacked around it by doing: request.removeAttribute("com.opensymphony.sitemesh.APPLIED_ONCE"); before doing the return new ModelAndView("forward:..."); which allows SiteMesh to decorate after the forward.Emotionality

© 2022 - 2024 — McMap. All rights reserved.