SpringMVC JavaConfig and Sitemesh with Maven

Tech stack used: Java 1.8, Spring MVC 4.2.2.RELEASE, Sitemesh 3.0.1, Java Servlet 3.0.1. Refer to project POM for more details.

The Maven project behind this article is publicly available on gitHub so feel free to check it out: https://github.com/gmihaylov840/SpringMVCSitemeshMaven.git

For those of you that don’t know yet, Sitemesh is a lightweight, web page decorating framework for Java Web apps. In order to used it, the web app has to be executing web container with Java Servlet specification 2.3 or later.

It’s developed with one specific pattern in mind that you’ve may already have guessed. That’s right, it’s Gang of Four’s Decorator pattern.
I won’t discuss the pattern here, but will try to make article about it in the Design Patterns section as soon as possible. Just bear in mind that this pattern adds functionality to a target object by wrapping it into a bigger decorator object into which new, required fields are added by composition.

That is exactly how Sitemesh works. It takes requested resource from http request e.g. http://www.theforceawakenssucksbigtime.com/JJAbrams-is-now-learning-how-to-plot-a-story/home.jsp, home.jsp being the requested resource here, and pulls out its content, which is then placed into a bigger page called Decorator. The advantage here is that the Decorator can have other elements like header, footer, navigation, adds, etc. that will be positioned around the original home.jsp content. This is called decorating. The final result is HTML response with home.jsp content decorated with additional header, footer, navigation, adds or anything else placed into the Decorator file. So that is how Sitemesh “wrapps” the requested resource’s content into a bigger page thus adding more functionality.

Built in this way, Sitemesh has many advantages:

  • Separation of look and feel from the data;
  • Additional templates could be loaded for Mobile Devices;
  • Integration with other web frameworks (Freemarker, WebWorks, Spring, Struts, Velocity);
  • Eliminates the need to create multiple web-apps for different audiences by allowing the decorator to be changed according to the user-agent or a request parameter(s) (e.g. printable version);

I highly recommend you to checkout both available documentations: Sitemesh v.2 and Sitemesh v.3. Of course you’ll only use v.3, because it’s the latest one (duhh..), BUT v.2 has better schematics and examples that will help you get a grasp on the workflow even though v.3 completely rewrited Sitemesh’s core engine.

Sitemesh workflow

Let’s start with workflow diagram:

Well…that says it all, but let’s go over it anyway for sake of clarity:

  1. Browser sends HTTP request for a resource Menu.jsp. After Menu.jsp has been compiled (with coffee price list…is cappuccino overpriced or what?) a response is send back from JSP container to the server, so the server can push it back to the client;
  2. Before the response is pushed to the client it is intercepted and decorated by Sitemesh’s decorator file – browser-theme.jsp, adding company specific header and footer to the HTML response;
  3. The decorated HTML response is finally send to the client browser;

Mobile app workflow will not be discussed in this post.

In terms of workflow, Sitemesh is a servlet filter and as such it has the ability to intercept incoming requests before they hit the web container and outgoing responses before they leave the server. Sitemesh is interested only in intercepting responses, because decoration should be the final change made to the HTML before returning it to the client. Servlet filters are nothing new to the Java Servlet specification and there are many predefined ones that can be used out of the box. The most popular one is the CharacterEncodingFilter that sets the encoding of all incoming requests to UTF-8 before they hit the web container;

Feel confused about filters? Maybe Sitemesh’s logical flow diagram will help you out:

Configuring SpringMVC via JavaConfig

As usual I’ll start with setting-up SpringMVC in JavaConfig mode.

ApplicationConfiguration class is the main configuration for this app. It usually defines beans for mappings and view resolvers, but in this simple example no such beans are necessary. Since the app will be serving static HTML resources this class only needs resource handler mappings.

You will notice later that it’s actually serving JSP pages instead of HTML and that is because right now there is a bug related to HTML response headers. The JPSs don’t actually have any dynamic data in them so for this example the app will treat them as static HTML
 
package sitemesh.mvc.setup;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
@EnableWebMvc
public class ApplicationConfiguration extends WebMvcConfigurerAdapter {

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/decorators/**").addResourceLocations("/decorators/");
		registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
	}

}

The @Configuration annotation marks this class as spring config that can later be loaded into app’s root context.
The @EnableWebMvc enables MVC behaviour (servlets, controllers, views…) for Spring. It is equivalent to in XML config.

And then there is the ApplicationInitializer class:

 
import java.util.EnumSet;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import sitemesh.filter.MySitemeshFilter;

public class ApplicationInitializer implements WebApplicationInitializer {

	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {

		createAppRootContext(servletContext);

		addSitemeshFilterToServletContext(servletContext);

		registerDispatcherServlet(servletContext);
	}

	private void createAppRootContext(ServletContext servletContext) {
		// Create the 'root' Spring application context
		AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
		rootContext.register(ApplicationConfiguration.class);

		// Manage the life-cycle of the root application context
		servletContext.addListener(new ContextLoaderListener(rootContext));
	}

	private void addSitemeshFilterToServletContext(ServletContext servletContext) {
		FilterRegistration.Dynamic sitemesh = servletContext.addFilter("sitemesh", new MySitemeshFilter());
		EnumSet<DispatcherType> sitemeshDispatcherTypes = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD);
		sitemesh.addMappingForUrlPatterns(sitemeshDispatcherTypes, true, "/*");
	}

	private void registerDispatcherServlet(ServletContext servletContext) {
		ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(
				new AnnotationConfigWebApplicationContext()));
		dispatcher.setLoadOnStartup(1);
		dispatcher.addMapping("/");
	}

}

Method createAppRootContext() creates the root app context by passing in the ApplicationConfiguration class as I mentioned earlier. That way all beans and configurations from ApplicationConfiguration class will be available in the root app context.

The addSitemeshFilterToServletContext() method adds Sitemesh filter to the servlet context.

The addMappingForUrlPatterns method defines URL pattern on which the filter will be executed. In this case – on all requests.

The registerDispatcherServlet() method registers single dispatcher servlet for this spring app.

Configuring Sitemesh

MySitemeshFilter class is used instead of the default ConfigurableSitemeshFilter class, because this is the only way to specify Sitemesh configuration when using JavaConfig. If case of XML config all definition in MySitemeshFilter class would be defined in sitemesh3.xml file in WEB-INF folder.

package sitemesh.filter;

import org.sitemesh.builder.SiteMeshFilterBuilder;
import org.sitemesh.config.ConfigurableSiteMeshFilter;

public class MySitemeshFilter extends ConfigurableSiteMeshFilter {

	@Override
	protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
		builder.addDecoratorPath("/*", "/decorators/decorator.html").addExcludedPath("/excluded/*")
				.addExcludedPath("/resources/*").addExcludedPath("/decorators/*");
	}
}

The most important thing to notice here is the builder.addDecoratorPath(“/*”, “/decorators/decorator.html”) line. It tells Sitemesh which decorator file to use for that URL pattern.
Next, Sitemesh is being instructed to NOT decorate resources in excluded, resources, and decorators folders. I added them because it makes no sense to decorate static resources like images or the decorator file itself.

Project Structure

This application will simulate basic coffee shop with root folder “webapp” and application name “myApp”.

Sitemesh’s decorator files reside in “decorators” folder as stated in MySitemeshFilter class: addDecoratorPath(“/*”, “/decorators/decorator.html”).

All files located in the “pages” folder, menu.jsp and hours.jsp, will be decorated once requested by client browser.

The files located in the “excluded” folder will NOT be decorated by Sitemesh as stated in MySitemeshFilter class with .addExcludedPath(“/excluded/*”).

The folder resources contains footer and header images that are used by the decorator.

Running the Project

That part is easy thanks to Maven. Just issue the following command to Maven “jetty:run” and embedded Jetty server will automatically get deployed and started.

To view decorated files, open browser and request http://localhost:8080/myApp/pages/menu.jsp or http://localhost:8080/myApp/pages/hours.jsp.

Requesting will serve decorated pages with the following flow:

  1. Dispatcher servlet will compile menu.jsp and return HTML response to the server;
  2. Before the response is returned to the browser it is intercepted by Sitemesh filter and decorated using decorator.html file that will add header and footer images around the original content of menu.jsp.
  3. Once decorator is completed, the decorated HTML response is returned to the client browser.

Result will look like this:

The same flow will decorate “http://localhost:8080/myApp/pages/hours.jsp”, result:

To view the non-decorated pages for comparison, simply request from the excluded folder http://localhost:8080/myApp/excluded/menu.jsp or http://localhost:8080/myApp/excluded/hours.jsp.

Results are:

Links & Resources

Project repository on gitHub: https://github.com/gmihaylov840/SpringMVCSitemeshMaven.git
Sitemesh documentation pages for v.2 and v.3: http://wiki.sitemesh.org/wiki/
Gang of Four, Decorator pattern on Wikipedia: https://en.wikipedia.org/wiki/Decorator_pattern

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s