Overview

SiteMesh is a web-page layout and decoration framework and web- application integration framework to aid in creating large sites consisting of many pages for which a consistent look/feel, navigation and layout scheme is required.

Integrating WebWork with SiteMesh is amazingly simple: you don't have to do anything in fact. WebWork stores all its value stack information in the request attributes, meaning that if you wish to display data that is in the stack (or even the ActionContext) you can do so by using the normal tag libraries that come with WebWork. That's it!

ActionContextCleanUp

In WebWork's Architecture, the standard filter-chain optionally starts with the ActionContextCleanUp filter, followed by other desired filters. Lastly, the FilterDispatcher handles the request, usually passing it on to the ActionMapper. The primary purpose of the ActionContextCleanUp is for SiteMesh integration. This tells the FilterDispatcher when exactly, to clean-up the request. Otherwise, the ActionContext may be removed before the decorator attempts to access it.

Warning
If ActionContext access is required within the decorators, the ActionContextCleanUp filter must be placed at the beginning of the filter-chain.

For more information, see the javadocs of the ActionContextCleanUp filter:

Special filter designed to work with the FilterDispatcher and allow for easier integration with SiteMesh. Normally, ordering your filters to have SiteMesh go first, and then FilterDispatcher go second is perfectly fine. However, sometimes you may wish to access WebWork-features, including the value stack, from within your SiteMesh decorators. Because FilterDispatcher cleans up the ActionContext, your decorator won't have access to the date you want.

By adding this filter, the FilterDispatcher will know to not clean up and instead defer cleanup to this filter. The ordering of the filters should then be:

  • this filter
  • SiteMesh filter
  • FilterDispatcher

Velocity and FreeMarker Decorators

WebWork provides extension of the SiteMesh PageFilter that assist with integration with Velocity and FreeMarker. We strongly recommend using these filters, instead of the support provided by SiteMesh, because they also will provide the standard variables and Tags that you are used to when created views in your favoriate template language.

Velocity

If you are using Velocity for your SiteMesh decorators, we recommend using the VelocityPageFilter. This is an extension of the SiteMesh PageFilter, which should be placed in the web.xml in between the ActionContextCleanUp and the FilterDispatcher. Now the Velocity decorators will have access to WebWork variables such as $stack and $request.

<filter>
    <filter-name>webwork-cleanup</filter-name>
    <filter-class>com.opensymphony.webwork.dispatcher.ActionContextCleanUp</filter-class>
</filter>
<filter>
    <filter-name>sitemesh</filter-name>
    <filter-class>com.opensymphony.webwork.sitemesh.VelocityPageFilter</filter-class>
</filter>
<filter>
    <filter-name>webwork</filter-name>
    <filter-class>com.opensymphony.webwork.dispatcher.FilterDispatcher</filter-class>
</filter>

<filter-mapping>
    <filter-name>webwork-cleanup</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>sitemesh</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>webwork</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

FreeMarker

If you are using FreeMarker for your SiteMesh decorators, we recommend using the FreeMarkerPageFilter. This is an extension of the SiteMesh PageFilter, which should be placed in the web.xml in between the ActionContextCleanUp and the FilterDispatcher. Now the FreeMarker decorators will have access to WebWork variables such as ${stack} and ${request}.

<filter>
    <filter-name>webwork-cleanup</filter-name>
    <filter-class>com.opensymphony.webwork.dispatcher.ActionContextCleanUp</filter-class>
</filter>
<filter>
    <filter-name>sitemesh</filter-name>
    <filter-class>com.opensymphony.webwork.sitemesh.FreeMarkerPageFilter</filter-class>
</filter>
<filter>
    <filter-name>webwork</filter-name>
    <filter-class>com.opensymphony.webwork.dispatcher.FilterDispatcher</filter-class>
</filter>

<filter-mapping>
    <filter-name>webwork-cleanup</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>sitemesh</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>webwork</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

The following variables are available to the decorating freemarker page :-

  • ${title} - content of <title> tag in the decorated page
  • ${head} - content of <head> tag in the decorated page
  • ${body} - content of t<body> tag in the decorated page
  • ${page.properties} - content of the page properties

With the following decorated page :-

<html>
    <meta name="author" content="tm_jee" />
    <head>
        <title>My Title</title>
        <link rel="stylesheet" type="text/css" href="mycss.css" />
        <style type="text/javascript" language="javascript" src="myjavascript.js"></script>
    </head>
    <body<
        <h1>Sample</h1>
    </body>
</html>

Properties Content
${title} My Title
${head} <link rel="stylesheet" type="text/css" href="mycss.css" /> <style type="text/javascript" language="javascript" src="myjavascript.js"></script>
${body} <h1>Sample</h1>
${page.properties.meta.author} tm_jee

Applying Freemarker decorator in tag form

Method 1: Using WebWork's Freemarker applydecorator Transform

This is the WebWork component that implements Freemarker's ApplyDecorator Transform. To use this Freemarker Transform, it needs to be enabled in webwork.properties (which is enabled by default)

webwork.freemarker.sitemesh.applyDecoratorTransform = true

An example of usage would be as follows:-

In Sitemesh's decorators.xml

  <decorators defaultdir="/WEB-INF/decorators">
  	....
     <decorator name="panel" page="/panelDecorator.ftl" />
  </decorators*gt;

Decorator (panelDecorator.ftl)

 <table border="1">
   <tr>
   	<td>${title}</td>
   </tr>
   <tr>
     <td>${body}</td>
   </tr>
 </table>

Freemarker page that uses decorator

	 <html> 
   <head>
      <title>some title</title>
   </head>
   <body>
     <h1>some body title</h1>
     <@sitemesh.applydecorator name="panel" page="/pages/pageToBeDecorated.ftl" />
   </body>
  </html>

An example of pageToBeDecorated.ftl

 <html>
   <head>
      <title>Panel Title</title>
   </head>
   <body>
      Panel Content
   </body>
 </html>

The nett outcome would be:-

  <html>
    <title>some title&l/title>
  <body>
    <h1>some body title</h1>
    <table border="1">
      <tr>
      	<td>Panel Title</td>
      </tr>
      <tr>
         <td>Panel Content</td>
      </tr>
    </table>
  </body>
  </html>

The following are method hooks available to ApplyDecoratorBean and its subclass

  • getFreemarkerTemplate(String templatePath) - create a Freemarker Template based on the template path given
  • parsePageFromContent(String content) - returns a Sitemesh Page object based on the content as the to-be-decorated-page
  • parsePageFromAbsoluteUrl(String absoluteUrl) - returns a Sitemesh Page object using the absoluteUrl to get the content of the to-be-decorated-page
  • parsePageFromRelativeUrlPath(String relativeUrl) - returns a Sitemesh Page object using the relativeUrl to get the content of the to-be-decorated-page.
  • getSitemeshFactory() - returns a Sitemesh Factory object
  • getPageParser(String contentType) - returns a Sitemesh PageParser object
  • getDecorator(HttpServletRequest request, String decoratorName) - returns a Sitemesh Decorator object with the decoratorName supplied.
  • deduceLocale(ActionInvocation invocation, Configuration freemarkerConfiguration) - deduce the Locale from invocation else use the Locale supplied by Freemarker
  • createModel() - create a Freemarker model for the template

Method 2: Using Sitemesh's ApplyDecorator Tag

Add Sitemesh's FreemarkerDecoratorServlet to web.xml

<servlet>
   <servlet-name>freemarkerDecoratorServlet</servlet-name>
   <servlet-class>com.opensymphony.module.sitemesh.freemarker.FreemarkerDecoratorServlet</servlet-class>
 </servlet>
 <servlet-mapping>
   <servlet-name>freemarkerDecoratorServlet</servlet-name>
   <url-pattern>*.dec</url-pattern>
 </servlet-mapping>

Add in Sitemesh decodator in decorator.xml eg.

<decorators>
     ...
     <decorator name="panel" page="panelDecorator.dec" />
  </decorators>

Use Sitemesh's ApplyDecorator tag in page eg.

<#assign page=JspTaglibs['/WEB-INF/sitemesh-page.tld'] />
 ...
   <@page.applyDecorator name="panel" page="/pageToBeDecorated.ftl" />
 ...

An example of pageToBeDecorated.ftl

<html>
  <head>
    <title>Some Title</title>
  </head>
  <body>
     Some Body
  </body>
 </html>

An example of panel.dec

<table border="1">
   <tr>
     <td>${title}</td>
   </tr>
   <tr>
     <td>${body}</td>
   </tr>
 </table>

Nett effect after applying decorator

<html>
    ...
    <table border="1">
      <tr>
        <td>Some Title</td>
      </tr>
      <tr>
         <td>Some Body</td>
      </tr>
    </table>
    ...
  </html>