Velocity Tools

Subprojects

Docs

Development

Velocity News Feed

VelocityLayoutServlet (VLS) Overview

This is an extension to the basic VelocityViewServlet. It provides a simple layout control and customizable error screens for Velocity Tools based projects. VelocityTools is distributed with an example app demonstrating the use of this servlet.

Installation

Since this class is an extension of the VelocityViewServlet (VVS), to use it simply change the servlet-class value of the web.xml entry to the following class:

org.apache.velocity.tools.view.servlet.VelocityLayoutServlet

Configuration Settings

Three settings can be added to velocity.properties to control the VLS, or the following default values will be used:

# Filepath for error template,
#  relative to web application root directory
tools.view.servlet.error.template = Error.vm

# Directory for layout templates,
#  relative to web application root directory
tools.view.servlet.layout.directory = layout/

# Filepath of the default layout template
#  relative to the layout directory
#  NOT relative to the root directory of the webapp!
tools.view.servlet.layout.default.template =  Default.vm</sourcecode></pre>

Layouts

Now, in your layout templates, the only thing you really need is the screen content reference. So an acceptable layout template could be:

$!screen_content

...but that would make this whole thing an idiotic waste of time. At the least, you'll probably want to do something along these lines:

<html>
<head>
  <title>$!page_title</title>
</head>
<body>
  $screen_content
</body>
</html>

This saves you the trouble of doing the basic ,, and tags in every single screen. That's the point of layouts: to save effort and eliminate redundancy. Note that this still lets the inner screen control the title of the page. This works because the layout template is blessed by the VLS with access to the same context as the screen after the screen is done with it. Just do a #set( $page_title = "Hello" ) in the screen.

Alternative Layouts

VLS provides several ways to specify an alternate template for a requested page:

  1. Specify the layout in the request attribute

    request.setAttribute("layout", "MyOtherLayout.vm");
    
  2. Specify the layout by overloading the VelocityLayoutServlet.findLayout(HttpServletRequest) function

    @Override
    public String findLayout(HttpServletRequest request)
    {
        if (request.getParameter("change_layout") != null) return "MyOtherLayout.vm";
        else return super.findLayout(request)
    }
    
  3. Specify the layout in the requested screen.

In the requested screen, put a line like this:

#set( $layout = "MyOtherLayout.vm" )

This will direct the VLS to use "MyOtherLayout.vm" instead of "Default.vm". Setting the layout in this fashion will override any layout set by the request parameters.

Those of you who are (or were) Turbine or Struts users will probably want to do more than just set the layout and screen content. You want to include arbitrary "tiles" or "navigations", right? Well, thanks to Velocity's built-in #parse directive, this is easy.

First, create your "tile" as a separate template file like:

<div id="footer">I made this!</div>

For creativity's sake, we'll pretend this code is in a file named "Footer.vm" that is located in the root of my webapp like my other non-layout templates.

<html>
<head>
  <title>$!page_title</title>
</head>
<body>

$screen_content

#parse('Footer.vm')

</body>
</html>

Easy, eh?

Now, what if you have a lot of different "footer" files and you want your screen to decide which one will be used? No problem! Do something like this:

<html>
<head>
  <title>$!page_title</title>
</head>
<body>

$screen_content

#parse( $screen_footer )

</body>
</html>

and in your screen, just do #set( $screen_footer = 'FooFooter.vm' ).

Remember, your #parsed footer template will have access to the same velocity context as your layout, which gets the screen's context once the screen is done with it. This lets you set variables for the layout and footer to use from your screens.

Error Screen

Ok, the idea here is pretty simple. If an uncaught exception or error is thrown at some point during the processing of your screen and layout, the error() method of the VLS is called. This overrides the default error() method of the VelocityViewServlet to render a template instead of hardcoded html.

This error screen will be rendered within a layout under the same rules as any other screen, and will have the following values placed in its context to help you debug the error:

Key available to Template Value
$error_cause java.lang.Throwable that was thrown
$stack_trace captured output of $error_cause.printStackTrace()

In the event that a MethodInvocationException is behind the calling of error(), the root cause is extracted from it and dealt with as described above. But, since template reference behavior is partly at fault here, the VLS will also add the MethodInvocationException itself to the context as $invocation_exception. This allows you to discover the reference and method call that triggered the root cause. To get those, do something like this in your error template:

#if( $invocation_exception )
    oh joy! it's a MethodInvocationException!

    Message: $invocation_exception.message
    Reference name: $invocation_exception.referenceName
    Method name: $invocation_exception.methodName
#end