Search code examples
javaspringjerseyfreemarkersitemesh

Sitemesh and Freemarker with Jersey resources


I have got a Jersey-based application, which for HTML requests uses Freemarker to generate HTML from templates programatically;

@GET
@Produces("text/html")
public Response getResources(@PathParam("name") String name) {
    LOG.info("got a request for " + name);
    Map<String, Object> model = new HashMap<String, Object>();
    model.put("name", name);
    //lookup some data for name;
    model.put("somedata", somedata);
    StringWriter out = new StringWriter();
    configuration.getTemplate("template.ftl").process(model, out);
    return Response.ok().entity(out.toString()).build();
}

So the configuration instance = freemarker.template.Configuration which is initialised in Spring;

<bean id="configuration" class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
    <property name="templateLoaderPath" value="/WEB-INF/template/path"/>
</bean>

Now, I've in web.xml the Jersey controller, the Sitemesh filter, and the Sitemesh-Freemarker servlet set up;

<servlet>
  <servlet-name>JerseySpringNode</servlet-name>
  <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>JerseySpringNode</servlet-name>
  <url-pattern>/mypath/*</url-pattern>
</servlet-mapping>

The sitemesh filter:

<filter>
  <filter-name>sitemesh</filter-name>
  <filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>sitemesh</filter-name>
  <url-pattern>/mypath/*</url-pattern>
  <dispatcher>REQUEST</dispatcher>
  <dispatcher>FORWARD</dispatcher>
</filter-mapping>

And the servlet:

<servlet>
  <servlet-name>sitemesh-freemarker</servlet-name>
  <servlet-class>com.opensymphony.module.sitemesh.freemarker.FreemarkerDecoratorServlet</servlet-class>
  <init-param>
    <param-name>TemplatePath</param-name>
    <param-value>/</param-value>
  </init-param>
  <init-param>
    <param-name>default_encoding</param-name>
    <param-value>ISO-8859-1</param-value>
  </init-param>
  <load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>sitemesh-freemarker</servlet-name>
  <url-pattern>*.dec</url-pattern>
</servlet-mapping>

(we use ".dec" to mark templates that are decorators). Decorator.xml

<?xml version="1.0" encoding="UTF-8"?>
  <decorators defaultdir="/decorators">
    <decorator name="main" page="header_and_footer.dec">
      <pattern>/*</pattern>
    </decorator>
</decorators>

Now, this works fine as it is. HTML pages are decorated with sitemesh.

The only problem that we currently have, is that we now need to inject into the decorators parameters which are determined from Spring (such as things from the user principle, things out of the request context, or stuff from the database, e.g. some information from that "somedata" property).

Given we are not using Spring WebMVC anywhere in this application, how do we wire up a freemarker servlet that can access this information? Even if it's a separate Spring bean that requires to be wired up with its dependencies, that's OK. Alternatively is there some way we can programatically invoke sitemesh inside the original Jersey resource method?

I did found a solution by a "Ted Young" on the web but it's seemingly partial and doesn't work for me (also it requires to use SpringWebMVC, which is not optimal for me at this time).


Solution

  • Probably the easiest way would be to integrate Jersey and Spring - this results in Spring doing all of your dependency injection work.

    Here's the web.xml entry:

     <!--  Configure Jersey in this application. -->
      <servlet>
        <servlet-name>jersey</servlet-name>
        <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
    <!-- want a custom Jersey application class? do that here.
        <init-param>
          <param-name>javax.ws.rs.Application</param-name>
          <param-value>org.example.jersey.MyJerseyApp</param-value>
        </init-param>
    -->
        <!-- Spring managed resources do not need to be listed here. Leave out if empty -->
        <init-param>
          <param-name>com.sun.jersey.config.property.packages</param-name>
          <!--
          <param-value>org.example.jersey.package;org.example.jersey.otherpackage</param-value>
        </init-param>
      </servlet>