Velocity

About

Community

Docs

Comparisons

Tools

Contents

  1. Introduction and Getting Started
  2. Resources
  3. How Velocity Works
  4. The Context
  5. Using Velocity in Servlets
  6. Using Velocity in General Applications
  7. Configuration Keys and Values
  8. Configuring the Log System
  9. Configuring the Resource Loaders (template loaders)
  10. Velocity and XML
  11. Summary

Introduction

Velocity is a Java-based template engine, a simple and powerful development tool that allows you to easily create and render documents that format and present your data. In this guide, we hope to give an overview of the basics of development using Velocity, focusing on the two main areas for Velocity usage :

  • servlet-based WWW development
  • general application use
You will see that there is no real difference between these, other than we make servlet development with Velocity very easy if you use our provided class VelocityServlet as a base class for your servlet, and offer a utility class to help with application development.

Getting Started

While this information is found elsewhere on the Velocity site and in the documentation, it is included here for completeness. Getting Velocity running on your computer is very easy. Note that all directory references are relative the root of the Velocity distribution tree.

  1. Get the Velocity distribution. This is available as a nightly snapshot or directly from the CVS code repository. Either way is fine. For more information, go here.
  2. Go to the build directory in the distribution.
  3. Type ./build-velocity.sh jar under Unix, or build-velocity.bat jar under Windows. The major build targets are :
    • jar builds the complete Velocity jar in the bin directory. This jar will be called 'velocity-X.jar', where 'X' is the current version number. Unless you have specific storage space considerations, use this jar for convenience, as it includes everything you need.
    • jar-core builds a slimmer Velocity jar in the bin directory, called 'velocity-core-X.jar'. This jar contains the core Velocity functionality, and doesn't include example and utility things like Anakia, Texen or the VelocityServlet support baseclass.
    • jar-util builds a utility Velocity jar in the bin directory, called 'velocity-util-X.jar'. This jar contains utility code, specifically Anakia, Texen, and the WebMacro template conversion utility.
    • jar-servlet builds a utility Velocity jar in the bin directory, called 'velocity-servlet-X.jar'. This jar contains utility code for servlet programmers.
    • jar-j2ee builds a complete jar, like the 'jar' target, that includes any components that require J2EE support. Currently, this includes only org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader. As usual, it is placed in the bin directory, called 'velocity-j2ee-X.jar'. NOTE : if you wish to use this build target, you must place (or link) a copy of j2ee.jar into the build/lib directory. We do not provide it as part of the distribution. A good source is http://java.sun.com/
    • examples builds the example code in the example programs found in the examples directory. This build target will also build the forumdemo example project.
    • forumdemo builds the example webapplication in the examples/forumdemo directory.
    • docs builds these docs in the docs directory using Velocity's Anakia XML transformation tool. Allowing you to use Velocity templates in place of stylesheets - give it a try!
    • jarsrc bundles all the Velocity source code into a single jar, placed in the bin directory.
    • javadocs builds the Javadoc class documentation in the docs/api directory
    • test (after jar) will test Velocity against it's testbed suite of test routines
  4. While not required, testing the build is a good idea. Use the test target mentioned above.
  5. That's it! Velocity is ready to be used. Put the jar into your classpath, or into other appropriate places (such as the lib directory of your webapp if using with servlets)
  6. If you want to play with the examples, which is highly recommended when getting started, use build the examples via ./build-velocity.sh examples or build-velocity.bat examples.

Resources

There are quite a few resources and examples available to the programmer, and we recommend that you look at our examples, documentation and even the source code. Some great sources are :

  • The user and developer community : join us via the mail-lists.
  • Mail-list archives : http:// www.mail-archive.com is a good one. Type 'velocity' into the search box to see both our -user and -dev archives.
  • source code : src/java/... : all the source code to the Velocity project
  • application example 1 : examples/app_example1 : a simple example showing how to use Velocity in an application program.
  • application example 2 : examples/app_example2 : a simple example showing how to use Velocity in an application program using the Velocity application utility class.
  • servlet example : examples/servlet_example1 : a simple example showing how to use Velocity in a servlet.
  • Anakia application : examples/anakia : example application showing how to use Velocity for creating stylesheet renderings of xml data
  • Forumdemo web app : examples/forumdemo : working example of a simple servlet-based forum application
  • documentation : docs : all the generated documentation for the Velocity project in html
  • API documentation : docs/api : the generated Javadoc documentation for the Velocity project
  • templates : test/templates : a large collection of template examples in our testbed directory, these are a great source of useage examples of VTL, the Velocity Template Language
  • context example : examples/context_example : two examples showing how the Velocity context can be extended. For advanced users.
All directory references above are relative to the distribution root directory.

How Velocity Works
'The Fundamental Pattern'

When using Velocity in an application program or in a servlet (or anywhere, actually), you will generally do the following :

  1. Initialize Velocity. (You only do this once.)
  2. Create a Context object (more on what that is later).
  3. Add your data objects to the Context.
  4. Choose a template.
  5. 'Merge' the template and your data to produce the ouput.
In code, this looks like

import java.io.StringWriter;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.runtime.Runtime;
import org.apache.velocity.Template;
import org.apache.velocity.app.Velocity;

Velocity.init();

VelocityContext context = new VelocityContext();

context.put( "name", new String("Velocity") );

Template template = null;

try
{
   template = Runtime.getTemplate("mytemplate.vm");
}
catch( ResourceNotFoundException rnfe )
{
   // couldn't find the template
}
catch( ParseErrorException pee )
{
  // syntax error : problem parsing the template
}
catch( Exception e )
{}

StringWriter sw = new StringWriter();

template.merge( context, sw );

That's the basic pattern. It is very simple, isn't it? This is generally what happens when you use Velocity to render a template. You probably won't be writing code exactly like this - we provide a few tools to help make it even easier than this for both servlet and application programmers. Later on in this guide, we will talk about using Velocity in both servlets as well as general applications, and we discuss the tools we provide to make things easier. In each case, though, the above sequence is what is happening either explicitly, or behind the scenes.

The Context
The Basics

The concept of the 'context' is central to Velocity, and is a common technique for moving a container of data around between parts of a system. The idea is that the context is a 'carrier' of data between the Java layer (or you the programmer) and the template layer ( or the designer ). You as the programmer will gather objects of various types, whatever your application calls for, and place them in the context. To the designer, these objects, and their methods and properties, will become accessable via template elements called references. Generally, you will work with the designer to determine the data needs for the application. In a sense, this will become an 'API' as you produce a data set for the designer to access in the template. Therefore, in this phase of the development process it is worth devoting some time and careful analysis.

While Velocity allows you to create your own context classes to support special needs and techniques (like a context that accesses an LDAP server directly, for example), a good basic implementation class called VelocityContext is provided for you as part of the distribution.

VelocityContext is suitable for all general purpose needs, and we strongly recommended that you use it. Only in exceptional and advanced cases will you need to extend or create your own context implementation.

Using VelocityContext is as simple as using a normal Java Hashtable class. While the interface contains other useful methods, the two main methods you will use are

 public Object put(String key, Object value);
 public Object get(String key);

Please note that like a Hashtable, the value must be derived from java.lang.Object, and must not be null. Fundamental types like int or float must be wrapped in the appropriate wrapper classes.

That's really all there is to basic context operations. For more information, see the API documentation included in the distribution.

Support for Iterative Objects for #foreach()

As a programmer, you have great freedom in the objects that you put into the context. But as with most freedoms, this one comes with a little bit of responsibility, so understand what Velocity supports, and any issues that may arise. Velocity supports serveral types of collection types suitable for use in the VTL #foreach() directive.

  • Object [] Regular object array, not much needs to be said here. Velocity will internally wrap your array in a class that provides an Iterator interface, but that shouldn't concern you as the programmer, or the template author.
  • java.util.Collection Velocity will use the iterator() method to get an Iterator to use in the loop, so if you are implementing a Collection interface on your object, please ensure that iterator() returns a working Iterator.
  • java.util.Map Here, Velocity depends upon the values() method of the interface to get a Collection interface, on which iterator() is called to retrieve an Iterator for the loop.
  • java.util.Iterator USE WITH CAUTION : This is currently supported only provisionally - the issue of concern is the 'non-resettablity' of the Iterator. If a 'naked' Iterator is placed into the context, and used in more than one #foreach(), subsequent #foreach() blocks after the first will fail, as the Iterator doesn't reset.
  • java.util.Enumeration USE WITH CAUTION : Like java.util.Iterator, this is currently supported only provisionally - the issue of concern is the 'non-resettablity' of the Enumeration. If a 'naked' Enumeration is placed into the context, and used in more than one #foreach(), subsequent #foreach() blocks after the first will fail, as the Enumeration doesn't reset.
In the case of the Iterator and Enumeration, it is recommended that they are placed in the context only when it cannot be avoided, and you should let Velocity find the appropriate reusable iterative interface when that is sufficient and possible.

There are good reasons to use the java.util.Iterator interface directly (large data sets via JDBC, for example), but if it can be avoided, it might be better to use something else. By 'directly' , we meant doing something like :

  Vector v = new Vector();
  v.addElement("Hello");
  v.addElement("There");

  context.put("words", v.iterator() );

where the Iterator itself is placed into the context. Instead, if you simply did :


  context.put("words", v );

then all would be fine : velocity would figure out that Vector implement Collection (via List), and therefore will find the iterator() method, and use that to get a 'fresh' Iterator for its use each time it needs to. With just a plain Iterator (the first snippet above...), once velocity has used it in a #foreach(), Velocity has no way of getting a new one to use for the next #foreach() it is used in. The result is no output from any subsequent #foreach() blocks using that reference.

This above isn't meant to give the impression that iterating over collections in Velocity is something that requires great care and thought. Rather, the opposite is true, in general. Just be careful when you place an Iterator into the context.

Context Chaining

An innovative feature of Velocity's context design is the concept of context chaining. Also sometimes referred to as context wrapping, this advanced feature allows you to connect separate contexts together in a manner that makes it appear as one 'contiguous' context to the template.

This is best illustrated by an example :

 VelocityContext context1 = new VelocityContext();

 context1.put("name","Velocity");
 context1.put("project", "Jakarta");
 context1.put("duplicate", "I am in context1");

 VelocityContext context2 = new VelocityContext( context1 );

 context2.put("lang", "Java" );
 context2.put("duplicate", "I am in context2");

 template.merge( context2, writer );

In the code above, we have set up context2 such that it chains context1. This means that in the template, you can access any of the items that were put into either of the two VelocityContext objects, as long as there is no duplication of the keys used to add objects. If that is the case, as it is above for the key 'duplicate', the object stored in the nearest context in the chain will be available. In this example above, the object returned would be the string "I am in context2".

Note that this duplication, or 'covering', of a context item does not in any way harm or alter the covered object. So in the example above, the string "I am in context1" is alive and well, still accessable via context1.get("duplicate"). But in the example above, the value of the reference '$duplicate' in the template would be 'I am in context2', and the template has no access to the covered string 'I am in context1'.

Note also that you have to be careful when you are relying on the template to add information to a context that you will examine later after the rendering. The changes to the context via #set() statements in a template will affect only the outer context. So make sure that you don't discard the outer context, expecting the data from the template to have been placed onto the inner one.

This feature has many uses, the most common so far is providing layered data access and toolsets.

As mentioned before, the Velocity context mechanism is also extendable, but beyond the current scope of this guide. If you are interested, please see the classes in the package org.apache.velocity.context to see how the provided contexts are put together. Futher, there are a few examples in the examples/context_example directory in the distribution which show alternate implementations, including [a goofy] one that uses a database as the backing storage.

Please note that these examples are unsupported and are there for demonstration/educational purposes only.

Objects Created in the Template

There are two common situations where the Java code must deal with objects created at runtime in the template :

  1. When a template author calls a method of an object placed into the context by Java code.
  2. When a template adds objects to the context, the Java code can access those objects after the merge process is complete.
Dealing with these cases if very straighforward, as there are just a few things to know :
  • The VTL RangeOperator [ 1..10 ] and ObjectArray ["a","b"] are java.util.ArrayList objects when placed in the context or passed to methods. Therefore, your methods that are designed to accept arrays created in the template should be written with this in mind.
  • Numbers will be Integers in the context, and strings will be, of course, Strings.
  • Velocity will properly 'narrow' args to method calls, so calling setFoo( int i ) with an int placed into the context via #set() will work fine.

Other Context Issues

One of the features provided by the VelocityContext (or any Context derived from AbstractContext) is node specific introspection caching. Generally, you as a the developer don't need to worry about this when using the VelocityContext as your context. However, there is currently one known usage pattern where you must be aware of this feature.

The VelocityContext will accumulate intropection information about the syntax nodes in a template as it visits those nodes. So, in the following situation :

  • You are iterating over the same template using the same VelocityContext object.
  • Template caching is off.
  • You request the Template from getTemplate() on each iteration.
it is possible that your VelocityContext will appear to 'leak' memory (it is really just gathering more introspection information.) What happens is that it accumulates template node introspection information for each template it visits, and as template caching is off, it appears to the VelocityContext that it is visiting a new template each time. Hence it gathers more introspection information and grows. It is highly recommended that you do one or more of the following :

Using Velocity In Servlets
Programming

The most common use of Velocity is in the area of Java Servlet programming for the WWW. There are many reasons why Velocity is well suited for this task, one of the primary ones is Velocity's enforcement of the separation of the presentation (or view) layer from the code layer. There are many resources on this subject, including this.

The basic technique of using Velocity in a servlet environment is very simple. In a nutshell, all you must do is extend the provided VelocityServlet base class and implement a single method handleRequest(). That's really all that is required to use Velocity in your servlet development.

The following code is similar to the SampleServlet.java class included in the distribution in the examples directory.

public class SampleServlet extends VelocityServlet
{
    public Template handleRequest( Context context )
    {

        String p1 = "Jakarta";
        String p2 = "Velocity";

        Vector vec = new Vector();
        vec.addElement( p1 );
        vec.addElement( p2 );

        context.put("list", vec );

        Template template = null;

        try
        {
            template =  getTemplate("sample.vm");
        }
        catch( ResourceNotFoundException rnfe )
        {
          // couldn't find the template
        } 
        catch( ParseErrorException pee )
        {
          // syntax error : problem parsing the template
        }
        catch( Exception e )
        {}

        return template;
    }
}

Look familiar? With the exception of creating the context object, which is done for you by the VelocityServlet base class, and the merge() step which is also done for you by the VelocityServlet base class, it's identical to the basic code pattern we mentioned at the beginning of this guide. We take the context, add our application data, and return a template.

For advanced users, the VelocityServlet base class allows you to override parts of the handling of the request processing. The following methods may be overridden.

  • Properties loadConfiguration(ServletConfig config )
    Allows you to override the normal configuration mechanism and add or alter the configuation properties. This is useful for overriding or augmenting template and log paths, to set the absolute path into the webapp root at runtime.
  • Context createContext(HttpServletRequest request, HttpServletResponse response )
    Allows you to create the Context object yourself. This allows more advanced techniques, such as chaining or pre-loading with tools or data. The default implementation simply returns a VelocityContext object with the request and response objects placed inside. The request and response objects are wrapped in simple wrapper classes to avoid introspection problems that may occurr in some servlet container implementations. You can use the request and repsponse objects normally, accessing methods of either from the template. Just note that they aren't specifically javax.servlet.XXXX classes, if that is important to you.
  • void setContentType( HttpServletRequest request, HttpServletResponse response ) Allows you to examine the request and set the content type yourself, depending on the request or client. The default implementation sets the content type to be that either specified in the velocity.properties, if any, or the default, "text/html" if not specified in the properties.
  • void mergeTemplate( Template template, Context context, HttpServletResponse response ) Allows you to produce the output stream. The VelocityServlet uses a pool of very efficient Writer classes, so this would usually be overridden in special situations.
  • void requestCleanup( HttpServletRequest request, HttpServletResponse response, Context context ) Allows you to do any cleanup or resource reclamation at the end of the request processing. The default does nothing.
  • protected void error( HttpServletRequest request, HttpServletResponse response, Exception cause )
    Error handler that is called an exception occurrs in request processing. Default implementation will send a simple HTML message with stacktrace and exception information back to the user. Override for custom client messages and more advanced problem handling.
For further information, please see the Javadoc API documentation.

Deployment

When you deploy your Velocity-based servlets, you will certainly want to ensure that your properties file is used to configure the Velocity runtime. Under Tomcat, one way to accomplish this is by placing your velocity.properties file into the rootdirectory of your web app (webapps/appname ) and then add the following to your WEB-INF/web.xml file :

<servlet>
  <servlet-name>MyServlet</servlet-name>
  <servlet-class>com.foo.bar.MyServlet</servlet-class>
  <init-param>
      <param-name>properties</param-name>
      <param-value>velocity.properties</param-value>
  </init-param>
</servlet>

Assuming all is right, this will ensure that when MyServlet is loaded, it will use the velocity.properties file to initialize itself rather than relying on it's internal defaults.

Note that Velocity uses a singleton model for it's central core Runtime class, so it is a very good idea to put the velocity-XX.jar into the WEB-INF/lib directory in all web applications that use Velocity to ensure that the web app classloader is managing your Runtime instance, rather than putting it in the CLASSPATH or the top level lib directory of the servlet runner.

This deployment method will ensure that different web applications will not be subject to Velocity configuration conflicts.

Using Velocity In General Applications

As Velocity was designed to be a general-use tool, it is just as useful in general application programs as it is servlets. In general, you can use the same programming pattern discussed at the beginning of this guide, but there are a few utility methods provided for application use, just like we provide the VelocityServlet base class for ease of use in servlet programming. The only new responsibility you have as the application programmer is to initialize the Velocity runtime engine, but that is easy.

The Velocity Class

Velocity contains an application utility class called Velocity ( org.apache.velocity.app.Velocity ). The purpose of this class is to provide the necessary methods required to initialize Velocity, as well as useful utility routines to make life easier in using Velocity. This class is documented in the project's javadoc, so please look there for definitive details. This documentation is intended to be of a tutorial nature; therefore for compete API information, the Javadoc is the definitive source.

The Velocity runtime engine is a singleton instance that provides resource, logging and other services to all Velocity users running in the same JVM. Therefore, the runtime engine is initialized only once. You can attempt to initialize Velocity more than once, but only the first initialization will apply. The rest of the attempts will be ignored. The Velocity utility class currently provides five methods used in configuration of the runtime engine. The five configuration methods are :

  • setProperty( String key, Object o )
    Sets the property key with the value o. The value is typically a String, but in special cases can also be a comma-separated list of values (in a single String, ex."foo, bar, woogie") as well as other things that will arise.
  • Object getProperty( String key )
    Returns the value of the property key. Note that you must be aware of the type of the return value, as they can be things other than Strings.
  • init()
    Initializes the runtime with the default properties provided in the distribution.(These are listed below in the section pertaining to properties.)
  • init( Properties p )
    Initialize the runtime with the properties contained in the java.util.Properties object passed as an argument.
  • init( String filename )
    initilizes the runtime using the properties found in the properties file filename

Note that in each case, the default properties will be used as a base configuration, and any additional properties specified by the application will replace individual defaults. Any default properties not overwritten will remain in effect. This has the benefit that only the properties you are interested in changing need to be specified, rather than a complete set.

The most common approaches to initializing Velocity will be something like :

  1. Setup the configuration values you wish to set in a file in the same format as org/apache/velocity/runtime/defaults/velocity.properties (the default set), or in a java.util.Properties, and then call either init( filename ) or init( Properties )
  2. Set the configuration values individually using setProperty() and then call init(). This method is generally used by more advanced applications that already have their own configuration management system - this allows the application so configure Velocity based upon values it generates at runtime, for example.

Once the runtime is initialized, you can do with it what you wish.. This mostly revolves around rendering templates into an output stream, and the Velocity utility class allows you to do this easily. Currently, here are the methods and a brief description of what they do :

  • evaluate( Context context, Writer out, String logTag, String instring )
    evaluate( Context context, Writer writer, String logTag, InputStream instream )
    These methods will render the input, in either the form of String or InputStream to an output Writer, using a Context that you provide. This is a very convenienient method to use for token replacement of strings, or if you keep 'templates' of VTL-containing content in a place like a database or other non-file storage, or simply generate such dynamically.
  • invokeVelocimacro( String vmName, String namespace, String params[], Context context, Writer writer )
    Allows direct access to Velocimacros. This can also be accomplished via the evaluate() method above if you wish. Here you simply name the vm you wish to be called, create an array of args to the VM, a Context of data, and Writer for the output. Note that the VM args must be the 'keys' of the data objects in the Context, rather than literal data to be used as the arg. This will probably change.
  • mergeTemplate( String templateName, Context context, Writer writer )
    Convenient access to the normal template handling and rendering services of Velocity. This method will take care of getting and rendering the template. It will take advantage of loading the template according to the properties setting for the file resource loader, and therefore provides the advantage of file and parsed template caching that Velocity offers. This is the most efficient way to access templates, and is recommended unless you have special needs.
  • boolean templateExists( String name )
    Determines if a template name is able to be found by the currently configured resource loaders.

Once we know about these basic helpers, it is easy to write Java program that uses Velocity. Here it is :

import java.io.StringWriter;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.VelocityContext;

public class Example2
{
    public static void main( String args[] )
    {
        /* first, we init the runtime engine.  Defaults are fine. */

        Velocity.init();

        /* lets make a Context and put data into it */

        VelocityContext context = new VelocityContext();

        context.put("name", "Velocity");
        context.put("project", "Jakarta");

        /* lets render a template */

        StringWriter w = new StringWriter();

        Velocity.mergeTemplate("testtemplate.vm", context, w );
        System.out.println(" template : " + w );

        /* lets make our own string to render */

        String s = "We are using $project $name to render this.";
        w = new StringWriter();
        Velocity.evaluate( context, w, "mystring", s );
        System.out.println(" string : " + w );

    }
}

When we run this program, and have the template testtemplate.vm in the same directory as our program (because we used the default configuration properties, and the defaul place to load templates from is the current directory...), our output should be :

 template : Hi!  This Velocity from the Jakarta project.

 string : We are using Jakarta Velocity to render this.

where the template we used, testtemplate.vm, is

Hi!  This $name from the $project project.

That's all there is to it! Note that we didn't have to use both mergeTemplate() and evaluate() in our program. They are both included there for demonstration purposes. You will probably use only one of the methods, but depending on you application requirements, you are free to do what you wish.

This appears to be a little different from the 'fundamental pattern' that was mentioned at the beginning of this guide, but it really is the same thing. First, you are making a context and filling it with the data needed. Where this examples differs is that in the part of the above example where mergeTemplate() is used, mergeTemplate() is doing the work of getting the template and merging it for you, using the lower-level calls in the Runtime class. In the second example, you are making your template dynamically via the String, so that is analgous to the 'choose template' part of the process, and the evaluate() method does the merging for you using lower level calls.

So the example above sticks to the same simply pattern of using the Velocity template engine, but the utility functions do some of the repeated drudge work, or allow you other options for your template content other than template files.

Exceptions

There are three exceptions that Velocity will throw during the parse / merge cycle. This are additional to the exceptions that will come from IO problems, etc. They are found in the package org.apache.velocity.exception and are :

  1. ResourceNotFoundException
    Thrown when the resource managment system cannot find a resource (template) that was requested.
  2. ParseErrorException
    Thrown when a VTL syntax error is found when parsing a resource (template).
  3. MethodInvocationException
    Thrown when a method of object in the context thrown an exception during render time. This exception wraps the thrown exception and propogates it to the application. This allows you to handle problems in your own objects at runtime.
In each case, a message is put into the runtime log. For more information, see the Javadoc API documentation.

Miscellaneous Details

While the above example used the default properties, setting your own properties is very simple. All you have to do is make a properties file somewhere and pass the name of that file to the init(String) method of the Velocity utility class, or make a java.util.Properties object, add the desired properties and values, and pass that to the init(Properties) method. The latter method is convenient, because you can either fill it directly from a separate properties file via the load() method, or even better, you can fill it dynamically from your own application / framework's property set at runtime. This gives you the freedom to combine all of the properties for your app into one properties file.

If we wanted to use a different directory than the current directory to load our template from, we could do something like this :


 ...

import java.util.Properties;
 ...

 public static void main( String args[] )
    {
        /* first, we init the runtime engine.  */

        Properties p = new Properties();
        p.setProperty("resource.loader.1.resource.path", "/opt/templates");
        Velocity.init( p );

        /* lets make a Context and put data into it */

 ...

And, assuming you have a directory /opt/templates and the template testtemplate.vm is in there, then things would work just fine. If you try this and have a problem, be sure to look at the velocity.log for information - the error messages are pretty good for figuring out what is wrong.

Velocity Configuration Keys and Values

Velocity's runtime configuration is controlled by a set of configuration keys listed below. Generally, these keys will have values that consist of either a String, or a comma-separated list of Strings, referred to as a CSV for comma-separated values.

There is a set of default values contained in Velocity's jar, found in /src/java/org/apache/velocity/runtime/defaults/velocity.defaults, that Velocity uses as it's configuration baseline. This ensures that Velocity will always have a 'correct' value for it's configuration keys at startup, although it may not be what you want.

Any values specified before init() time will replace the default values. Therefore, you only have toconfigure velocity with the values for the keys that you need to change, and not worry about the rest. Further, as we add more features and configuration capability, you don't have to change your configuration files to suit - the Velocity engine will always have default values.

Please sees the section above Using Velocity In General Applications for discussion on the configuration API.

Below are listed the configuration keys that control Velocity's behavior. Organized by category, each key is listed with it's current default value to the right of the '=' sign.

Runtime Log

runtime.log = velocity.log
Full path and name of log file for error, warning, and informational messages. The location, if not absolute, is relative to the 'current directory'.

runtime.log.logsystem
This property has no default value. It is used to give Velocity an instantiated instance of a logging class that supports the interface org.apache.velocity.runtime.log.LogSystem., which allows the combination of Velocity log messages with your other application log messages. Please see the section
Configuring the Log System for more information.

runtime.log.logsystem.class = org.apache.velocity.runtime.log.AvalonLogSystem
Class to be used for the Velocity-instantiated log system.

runtime.log.error.stacktrace = false
runtime.log.warn.stacktrace = false
runtime.log.info.stacktrace = false
Turns on stacktracing for the three error categories. These produce a large amount of log output.

runtime.log.invalid.references = true
Property to turn off the log output when a reference isn't valid. Good thing to turn of in production, but very valuable for debugging.

Character Encoding

template.encoding = 8859_1
Encoding scheme to use. Currently used in VelocityServlet.

#foreach() Directive

directive.foreach.counter.name = velocityCount
Used in the #foreach() directive, defines the string to be used as the context key for the loop count. A template would access the loop count as $velocityCount.

directive.foreach.initial.value = 1
Default starting value for the loop counter reference in a #foreach() loop.

#include() and #parse() Directive

directive.include.output.errormsg.start =
directive.include.output.errormsg.end = ]]>
Defines the beginning and ending tags for an in-stream error message in the case of a problem with the #include() directive. If both the .start and .end tags are defined, an error message will be output to the stream, of the form '.start msg .end' where .start and .end refer to the property values. Output to the render stream will only occur if both the .start and .end (next) tag are defined.

directive.parse.maxdepth = 10
Defines the allowable parse depth for a template. A template may #parse() another template which itself may have a #parse() directive. This value prevents runaway #parse() recursion.

Resource Management

resource.loader = <name> (default = File)
Multi-valued key. Will accept CSV for value. Pulic name of a resource loader to be used. This public name will then be used in the specification of the specific properties for that resource loader. Note that as a multi-valued key, it's possible to pass a value like "file, class" (sans quotes), indicating that following will be configuration values for two loaders.

<name>.loader.description = Velocity File Resource Loader
Description string for the given loader.

<name>.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
Name of implementation class for the loader. The default loader is the file loader.

<name>.resource.loader.path = .
Multi-valued key. Will accept CSV for value. Root(s) from which the loader loads templates. Templates may live in subdirectories of this root. ex. homesite/index.vm This configuration key applies currently to the FileResourceLoader and JarResourceLoader.

<name>.resource.loader.cache = false
Controls caching of the templates in the loader. Default is false, to make life easy for development and debugging. This should be set to true for production deployment. When 'true', the modificationCheckInterval property applies. This allows for the efficiency of caching, with the convenience of controlled reloads - useful in a hosted or ISP environment where templates can be modifed frequently and bouncing the application or servlet engine is not desired or permitted.

<name>.resource.loader.modificationCheckInterval = 2
This is the number of seconds between modification checks when caching is turned on. When this is an integer > 0, this represents the number of seconds between checks to see if the template was modified. If the template has been modified since last check, then it is reloaded and reparsed. Otherwise nothing is done. When <= 0, no modification checks will take place, and assuming that the property cache (above) is true, once a template is loaded and parsed the first time it is used, it will not be checked or reloaded after that until the application or servlet engine is restarted.

To illustrate, here is an example taken right from the default Velocity properties, showing how setting up the FileResourceLoader is managed


resource.loader = file

file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = .
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 2

Velocimacro

velocimacro.library = VM_global_library.vm
Multi-valued key. Will accept CSV for value. Filename(s) of Velocimacro library to be loaded when the Velocity Runtime engine starts. These Velocimacros are accessable to all templates. The file is assumed to be relative to the root of the file loader resource path.

velocimacro.permissions.allow.inline = true
Determines of the definition of new Velocimacros via the #macro() directive in templates is allowed. The default value is true, meaning any template can define and use new Velocimacros. Note that depending on other properties, those #macro() statements can replace global definitions.

velocimacro.permissions.allow.inline.to.replace.global = false
Controls if a Velocimacro defind 'inline' in a template can replace a Velocimacro defined in a library loaded at startup.

velocimacro.permissions.allow.inline.local.scope = false
Controls 'private' templates namespaces for Velocimacros. When true, a #macro() directive in a template creates a Velocimacro that is accessable only from the defining template. This means that Velocimacros cannot be shared unless they are in the global or local library loaded at startup. (See above.) It also means that templates cannot interfere with each other. This property also allows a technique where there is a 'default' Velocimacro definition in the global or local library, and a template can 'override' the implementation for use within that template. This occurrs because when this property is true, the template's namespace is searched for a Velocimacro before the global namespace, therefore allowing the override mechanism.

velocimacro.context.localscope = false
Controls whether reference access (set/get) within a Velocimacro will change the context, or be of local scope in that Velocimacro.

String Interpolation

runtime.interpolate.string.literals = true
Controls interpolation mechanism of VTL String Literals. Note that a VTL StringLiteral is specifically a string using double quotes that is used in a #set() statement, a method call of a reference, a parameter to a VM, or as an argument to a VTL directive in general. See the VTL reference for further information.

Runtime Configuration

parser.pool.size = 20
This property sets the number of parsers that Velocity will create at startup and keep in a pool. The default of 20 parsers should be more than enough for most uses. In the event that Velocity does run out of parsers, it will indicate so in the log, and dynamically create them as needed. Note that they will not be added to the pool. This is a slow operation compared to the normal parser pooling, but this is considered an exceptional condition. If you see a log message, please increment this property.

Configuring the Log System

Velocity has a few nice logging features to allow both simplicity and flexibility. Without any extra configuration, Velocity will setup a file-based logger that will output all logging messages to a file called velocity.log in the 'current directory' where Velocity was initialized. For more advanced users, you may integrate your current logging facilities with Velocity to have all log messages sent to your logger.

Your options :

Making a custom logger class if very simple. The code below is a simple sketch of how you might do this in your own application.

Simple Example of a Custom Logger

Here is a simple example of how to integrate Velocity's logging system into your own application.


import org.apache.velocity.runtime.log.LogSystem;

...

public class MyClass implements LogSystem
{

...

    public MyClass()
    {
        ...

        try
        {
            /*
             *  register this class as a logger
             */
            
            Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, this );
            Velocity.init();
        }
        catch (Exception e)
        {
            /*
             *  do something
             */
        }             
    }

    /**
     *  This is the method that you implement for Velocity to call
     *  with log messages.
     */
    public void logVelocityMessage(int level, String message)
    {
        /*  do something useful */
    }
...
}
            
Configuring Resource Loaders

One of the fundamental and important parts about Velocity is the resource management system and the resource loaders. They are referred to as 'resources' here rather than 'templates' because the resource management system will also handle non-template reasources, specifically things that are loaded via the #include() directive.

The resource loader system if very flexible, allowing one or more resource loaders to be in operation at the same time. This allows tremendous flexibility in configuration and resource managment, and futher allows you to write your own resource loaders for your special needs.

There are currently four kinds of resource loaders that are included with Velocity, each described below. Note that in the example configuration properties given, a common name for the loader is shown (ex.'file' in file.resource.loader.path). This 'common name' may not work for your configuration. Please read the section on resource configuration properties to understand how this system works. Also, each of these loaders is located in the package org.apache.velocity.runtime.resource.loader.

  • FileResourceLoader : This loader gets resources from the filesystem. It's configuration properties include :
    • file.resource.loader.path = <path to root of templates>
    • file.resource.loader.cache = true/false
    • file.resource.loader.modificationCheckInterval = <seconds between checks>
    This is the default loader, and is configured, by default to get templates from the 'current directory'. In the case of using Velocity with servlets, this can be a problem as you don't want to have to keep your templates in the directory from which you start your servlet engine. Please see the section on developing servlets with Velocity for more information.
  • JarResourceLoader : This loader gets resource from specific jar files. It is very similar to the FileResourceLoader, except that you have the convenience of bundling your templates into jars. The properties are identical, except for jar.resource.loader.path, where you provide the full location of the jar(s) you wish to load resources from.
  • ClasspathResourceLoader : This loader gets resources from the classloader. While the classpath is a source of great pain and suffering in general, it is a very useful mechanism when working on a Servlet Spec 2.2 compliant servler runner. Tomcat 3.2 is an example of such. To use this loader effectively, all you must do is jar your templates, and put that jar into the WEB-INF/lib directory of your webapp. There are no configuration options to worry about, nor is the absolute vs. relative path an issue, as it is with Jar and File resource loaders.
  • DataSourceResourceLoader : This loader will load resources from a DataSource such as a database. This loader is not built as part of the standard build as it requires J2EE support. To build this loader, please download the J2EE distribution, move the j2ee.jar into the build/lib directory, and then build the new velocity jar with the jar-j2ee build target. For more information on this loader, please see the javadoc for the class org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader.

Configuration Examples

Configuring the resource loaders for Velocity is straightforward. The properties that control the are listed in the resource configuration section, for further reference.

The first step in configuring one or more resource loaders is do 'declare' them by name to Velocity. Use the property resource.loader and list one or more loader names. You can use anything you want - these names are used to associate configuration properties with a given loader.


  resource.loader = file

That entry declares that we will have a resource loader known as 'file'. The next thing to do is to set the important properties. The most critical is to declare the class to use as the loader :


  file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader

In this case, we are telling velocity that we are setting up a resource loadercalled 'file', and are using the class org.apache.velocity.runtime.resource.loader.FileResourceLoader to be the class to use. The next thing we do is set the properties important to this loader.

file.resource.loader.path = /opt/templates
file.resource.loader.cache = true
file.resource.loader.modificationCheckInterval = 2

Here, we set a few things. First, we set the path to find the templates to be /opt/templates. Second, we turned caching on, so that after a template or static file is read in, it is cached in memory. And finally, we set the modification check interval to 2 seconds, allowing Velocity to check for new templates.

Those are the basics. What follows are a few examples of different configuraitons.

Do-nothing Default Configuration : As the name says, there is nothing you have to do or configure to get the default configuration. This configuration uses the FileResourceLoader with the current directory as the default resource path, and caching is off. As a properties set, this is expressed as :

resource.loader = file

file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = .
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 0

Multiple Template Path Configuration : This configuration uses the FileResourceLoader with several directories as 'nodes' on the template search path. We also want to use caching, and have the templates checked for changes in 10 second intervals. As a properties set, this is expressed as :

resource.loader = file

file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = /opt/directory1, /opt/directory2
file.resource.loader.cache = true
file.resource.loader.modificationCheckInterval = 10

Dual Loader Configuration : This configuration sets up two loaders at the same time, the FileResourceLoaderm, and the ClasspathResourceLoader. The loaders are set-up such that the FileResourceLoader is consulted first, and then the ClasspathResourceLoader. This would allow you to qickly drop a template into the file template are to replace on of the templates found in the classpath (usually via a jar) without having to rebuild the jar.

resource.loader = file, class

file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = .
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 0

class.resource.loader.description = Velocity Classpath Resource Loader
class.resource.loader.class = org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader

Note that the ClasspathResourceLoader doesn't require much configuration.

Velocity and XML

Velocity's flexibility and simple template language makes it an ideal environment for working with XML data. Anakia is an example of how Velocity is used to replace XSL for rendering output from XML. The Velocity site, including this documentation, is generated from XML source using Anakia. The Jakarta site is also rendered using Anakia.

Generally, the pattern for dealing with XML in Velocity is to use something like JDOM to process your XML into a data structure with convenient Java access. Then, you produce templates that access data directly out of the XML document - directly though the JDOM tree. For example, start with an XML document such as :

<?xml version="1.0"?>

<document>
 <properties>
  <title>Developer's Guide</title>
  <author email="geirm@apache.org">Velocity Documentation Team</author>
 </properties>
</document>

Now make a little Java program that includes code similar to:

  ...

  SAXBuilder builder;
  Document root = null;

  try 
  {
     builder = new SAXBuilder(  "org.apache.xerces.parsers.SAXParser" );
     root = builder.build("test.xml");
  }
  catch( Exception ee)
  {}

  VelocityContext vc = new VelocityContext();
  vc.put("root", root );

  ...

(See the Anakia source for details on how to do this, or the Anakia example in the examples directory in the distribution.) Now, make a regular Velocity template :

  <html>
    <body>
      The document title is $root.getChild("document").getChild("properties").getChild("title").getText()
    </body>
   </html>
  </html>

and render that template as you normally would, using the Context containing the JDOM tree. Of course, this isn't the prettiest of examples, but it shows the basics - that you can easily access XML data directly from a Velocity template.

One real advantage of styling XML data in Velocity is that you have access to any other object or data that the application provides. You aren't limited to just using the data present in the XML document. You may add anything you want to the context to provide additional information for your output, or provide tools to help make working with the XML data easier. Bob McWhirter's Werken Xpath is one such useful tool - an example of how it is used in Anakia can be found in org.apache.velocity.anakia.XPathTool.

One issue that arises with XML and Velocity is how to deal with XML entities. One technique is to combine the use of Velocimacros when you need to render an entity into the output stream :


## first, define the Velocimacro somewhere

#macro( xenc $sometext )$tools.escapeEntities($sometext)#end

## and use it as

#set( $sometext = " < " )
<text>#xenc($sometext)</text>

where the escapeEntities() is a method that does the escaping for you. Another trick would be to create an encoding utility that takes the context as a constructor parameter and only implements a method:

  public String get(String key)
  {
     Object obj = context.get(key)
     return (obj != null) ? Escape.getText( obj.toString() ) : "";
  }

Put it into the context as "xenc". Then you can use it as :

<text>$xenc.sometext</text>

This takes advantage of Velocity's introspection process - it will try to call get("sometext") on the $xenc object in the Context - then the xenc object can then get the value from the Context, encode it, and return it.

Alternatively, since Velocity makes it easy to implement custom Context objects, you could implement your own context which always applies the encoding to any string returned. Be careful to avoid rendering the output of method calls directly, as they could return objects or strings (which might need encoding). Place them first into the context with a #set() directive and the use that, for example :

#set( $sometext = $jdomElement.getText() )
<text>$sometext</text>

The previous suggestions for dealing with XML entities came from Christoph Reck, an active participant in the Velocity community. We are very grateful for his [unknowing] contribution to this document, and hope his ideas weren't mangled too badly :)

Summary

We hope this brief guide was a helpful introduction to using Velocity in your Java projects, and thank you for you interest in Velocity. We welcome any and all comments you may have about this documentation and the Velocity template engine itself.

Please submit all detailed, thoughtful and constructive feedback through our mail lists.


Copyright © 1999-2001, Apache Software Foundation