This forum is now a read-only archive. All commenting, posting, registration services have been turned off. Those needing community support and/or wanting to ask questions should refer to the Tag/Forum map, and to http://spring.io/questions for a curated list of stackoverflow tags that Pivotal engineers, and the community, monitor.

Sitemesh with Velocity Decorators

May 16th, 2005, 01:45 PM

Hi,

I was using Spring + Sitemesh + Velocity, but my decoratorators were JSPs. Some months ago the Sitemesh project has released the support to Velocity decorators.
So, I've tested the new Sitemesh Servlet in my Spring based system, but it is not working. The new Sitemesh servlet is cacthing all http requests and don't pass it to Spring Controllers...

Comment

I found I little problem. The includes in my decorator, are not loading my macros. The decorator.vm and the pages in $body has access to the macro.vm. But the pages inlcuded by the decorator.vm, do not.
Algo, the included pages recognize the velocity templates. Just the macros are not beeing recognized.
That is my velocityConfig:

I think it is occuring because the included pages aren't passing by any Spring class, they are beeing loaded just by the velocity-sitemesh Servlet, and my macros are defined just in the Spring configs.

Kind regards,
Franklin Samir

Comment

i'm having the same issue (i have a side bar that always displays some summary information about the user that is stored in the SecurityContext created by acegi on authentication) - the problem is that the context is only used to render the template specifed by the View class and then it is thrown away.

i got around this by sub-classing the VelocityDecoratorServlet like this:

it works, but now i'm having the same problem w/ some of the velocity-tools (ie: NumberTool) - i don't want to have to edit this servlet every time i need to stick something extra into the context so my decorators can use it.

i'll post back once i've looked into this further - if anyone else has dealt w/ this before, i'd like to hear your suggestions.

Comment

ok - i'm not really seeing an elegate solution around this problem. sitemesh redispatches the decorator back to the VelocityDecoratorServlet, so there isn't a simple way to carry along any context that was created inside the VelocityView class.

it appears that the best way to handle this situation is to subclass the VelocityDecoratorServlet and populate the context w/ any values that you want available to all of your decorators.

however, what i don't like about this is i loose the ability to leverage spring's handling of the locale when creating instances of velocity-tools, etc.

i could go back and duplicate that code (subclassing the tools to pass in locale, etc), but that seems rather wasteful to me.

i'm thinking that i will subclass both the VelocityViewResolver and the VelocityView so that i can expose a method off the VelocityViewResolver that will give me the same initial VelocityContext that is used inside the VelocityView class. after that, i'll look up the view resolver inside my subclassed VelocityDecoratorServlet and chain it w/ the one passed via the method input.

does this seem like an acceptable solution? do the spring folks have another recommendation?

i'm curious to see just how much of that implementation is still required in the latest version of sitemesh, and will probably look to see how difficult it would be to just add it as native functionality and submit it as a patch.

i have a pretty good handle on what's going on (the english one the site is a bit bad), so if you have questions, feel free to ask.

Comment

it seems that the integration is proving to be more difficult then i expected - i can get everything to render, but the output from the applyDecorator method is ending up at the top of the template instead of the the place in the template where the $decorator.applyDecorator reference was found.

there seems to be some issue w/ the requests and dispatchers that i am unable to track down and unfortunately i don't have the time to continue on trying to track it down.

Comment

b/c i can't get enough of this topic, i figured out a workable solution for this...

i created a controller in spring that duplicates all the functionality of the VelocityDecoratorServlet and i just map this pattern:

**/*.vm

to that controller and define a url mapping for *.vm to be handled by the DispatcherServlet.

the only "issue" w/ the solution is that you need resolve against a known template and then override the template location to that of the decorator. the reason for this is that right now, the VelocityViewResolver throws an exception if it can't find the template, instead of returning null so the next resolver can be tried.

Comment

I had the same problem, but with Freemarker instead of Velocity. Basically I wanted the decorating markup (i.e. header, footer, and navigation sidebar) to contain not just hard-coded HTML but also things like:

* the username (for display in the logout link)
* various labels looked up from resource files
* an "onload" JavaScript command that depends on which decorated page is being displayed (i.e. on the login screen I want the username field to have default focus, whereas on some edit screen, I want the first text field to have default focus)

I ended up doing this (having used Velocity a lot, I'm sure you Velocity users could apply the same approach):

1. Created a shared Freemarker macro (in my Macros.ftl file) that converts all data required by the decorators (see above list) into HTML meta tags, like this (I've shown only two such tags, for brevity):

This is a non-ideal solution, in that the pages being decorated have to know about the pages that are decorating them (otherwise why would they have all those meta tags in them), but it does mean the decorating pages don't need access to the same model data or resource files that the decorated pages do.

Hope this helps, and if anyone has a more elegant solution, please let me know or just reply here!

Cheers,

Andrew

Comment

And what's wrong with letting decorating pages to have access to the same data model that the decorated pages have?

It seems that the problem is actually that decorators do not have any access to the data model because they are being processed by separate sitemesh filter, not in the normal fashion. That is where the voodoo dances begin. Can't figure why would anyone want to use SiteMesh in the first place.

The most natural way IMHO would be to use custom ViewResolver which would render the decorated page first in the page.body variable, and then, using the same data model, render the decorator (now that we have page.body rendered). The results should be sent to output.

We just have to figure the best way to specify which decorator for which page should be used.
This example also demonstrates that the page title can be defined right in the page.ftl, which particularly seems to be more natural location for this rather than some external xml configuration.

This way of things also provides natural and uniform support for i18n - I usually pass locale object in the data model, also a special messageSourceHelper bean which is a simple wrapper around Spring's MessageSource, and define a macro:

This way anyone could use all benefits of FreeMarker (or Velocity), feel free to access the data model and don't bother with some weird workarounds when it's that simple. Perhaps I'm missing something important that makes it seem like a simple stuff.

I'll probably give it a try and implement such a custom ViewResolver and won't even try to use SiteMesh when it makes such simple things difficult.
Should it work out fine, I'll post it here with more detailed samples. (I might be wrong that it involves just custom ViewResolver, perhaps it will take some custom Renderer as well - will have to dig in the Spring source code)

Comment

> use custom ViewResolver...
Sounds like a good idea! Please do post here again once you get it working - I'd like to know the details of how you merge the page and decorator templates.

> I usually pass locale object in the data model, also a special messageSourceHelper bean which is a simple wrapper around Spring's MessageSource...
AFAIK this is already done for you. I have my FreeMarker view resolver defined like this: