Sitemesh is beautiful web-page and layout decoration framework produced by OpenSymphony, which is mostly using in many projects over JEE™ platform at the present.

Sitemesh has many very useful qualities but it has one uncomfortable characteristic. It doesn’t support decorating of pages in projects with MVC architecture as we need.

What is Sitemesh?

As I wrote therein before, Sitemesh is web-page and layout decoration framework. It was developed to aid in creating large sites consisting of many pages for which a consistent look/feel, navigation and layout scheme is required.

More information you can find at Sitemesh homepage or in fantastic tutorial Advanced Sitemesh publicated at onJava.org.

What are Decorator Mappers?

Sitemesh provide many ways, how to choose a correct decorator for requiring page, so-called Decorator Mappers. One of the most using ways is a usage of ConfigDecoratorMapper.

ConfigDecoratorMapper

ConfigDecoratorMapper choose right decorator on base of decorators and their mappings listed in the config property (default ‘/WEB- INF/decorators.xml’).

But where is the problem?

The problem starts inside ConfigDecoratorMapper by wrong evaluation of following code in projects based on MVC architecture.



public Decorator getDecorator(HttpServletRequest request, Page page) {

//critical place

String thisPath = request.getServletPath();

if (thisPath == null) {

String requestURI = request.getRequestURI();

if (request.getPathInfo() != null) {

// strip the pathInfo from the requestURI

thisPath = requestURI.substring(0, requestURI.indexOf(request.getPathInfo()));

} else {

thisPath = requestURI;

}

}

String name = null;

try {

name = configLoader.getMappedName(thisPath);

} catch (ServletException e) {

e.printStackTrace();

}

Decorator result = getNamedDecorator(request, name);

return result == null ? super.getDecorator(request, page) : result;

}


Because, when we have mapped our dispatcher servlet of our MVC project on some context in web.xml, a variable thisPath will be the same as value of our context.

This is caused by following code:



String thisPath = request.getServletPath();


Well. Now thisPath will be evaluated only on part of requested URL e.g.

  1. aplication context is root
  2. requested URL is http://weblog.morosystems.cz/sitemesh/article
  3. thisPath is evaluated only on /

This is a problem, because we usually want to distinquish different decorators on base of whole URL. In this case, we can use only one decorator for whole project based on MVC architecture.

Solution

But we solved this problem. We used UrlPathHelper from distribution of Spring Framework and improve critical place of ConfigDecoratorMapper by following code:



UrlPathHelper urlPathHelper = new UrlPathHelper();

String thisPath = urlPathHelper.getPathWithinApplication(request);


Now, thisPath is evaluated by whole requested URL e.g.

  1. our application is still mapped on root context /
  2. requested URL is http://weblog.morosystems.cz/sitemesh/article
  3. our variable thisPath is evaluated on /sitemesh/article

This is right behavior as we need.

Distribution

We prepare a binary and source code morosystems-sitemesh-mvc-extension-1.0 of our class. You can download it here.

Installation of our solution

Installation is not difficult and is the same as configuration of ConfigDecoratorMapper in sitemesh.xml configuration file.

Conclusion

Our solution has only one negative. It is dependent on Spring Framework which may be a problem for common public. It is not problem for us, because we use Spring Framework in all our projects. Meanwhile. When we will need remove these dependencies from our code, we will do it and our solution we will present on our web again.

We hope that our modification of ConfigDecoratorMapper will be useful for you as much of it is useful for us.