Client and server-side templating with Velocity
By Sing Li2004-06-13
Velocity contexts
You can think of a context in velocity as a means to import Java objects for access within Velocity templates. This import must be done explicitly in Java coding. Unlike JSP code or JavaScript, there is no "natural" or "native way" for Velocity templates to access arbitrary Java objects. Only explicitly imported Java objects will be available within a Velocity template.
You can obtain a Velocity context by creating an instance of the org.apache.velocity.context.Context class. You can then attach objects that are to be imported for template use to the context using the put(key,value) method of the context. The key will be a string name that will appear as an available reference inside the templates. In production scenarios, graphic or Web designers may be in charge of creating and maintaining templates, while Java developers provide the set of objects that will be accessible inside the templates. In these cases, the designers and developers will collaborate by agreeing on the set of objects and their available properties. The attached attributes in Velocity context will be the main interfacing mechanism.
Accessing context attributes in templates
Take a look at the included example code (see Resources) for a standalone parser. Look under the \code\src directory. For example, in our com.ibm.dvworks.velocity.VelocityParser class, we have created and added two attributes to the Velocity context, as shown in Listing 13:
Listing 13. Creating an instance of Velocity in our VelocityParser class
public static void main(String[] args) {
VelocityParser velInstance = new VelocityParser(args[0]);
velInstance.addToContext( "treeFarm",
new String [] { "redwood", "maple", "oak", "pine" });
velInstance.addToContext( "title", "A Tree Farm");
velInstance.addToContext( "date", new java.util.Date());
velInstance.addToContext("fmtr",
new org.apache.velocity.app.tools.VelocityFormatter(
velInstance.getCurrentContext()));
velInstance.processTemplate();
}
The attribute treeFarm is an ArrayList of tree names. The title attribute is a scalar string. Once attached to the context and passed in during the merge operation, these attributes are immediately usable within the Velocity templates. The template in Listing 14 uses these two attributes. You can find it in \code\app\treectx.vm.
Listing 14. Using the $treeFarm context attribute reference
<table>
<tr><td>$title</td></tr>
#foreach $name in $treeFarm
<tr><td>
$name is a big tree!
</td></tr>
#end
</table>
After merging, the output looks like Listing 15:
Listing 15. Merged output from the template
<table>
<tr><td>A Tree Farm</td></tr>
<tr><td>
redwood is a big tree!
</td></tr>
<tr><td>
maple is a big tree!
</td></tr>
<tr><td>
oak is a big tree!
</td></tr>
<tr><td>
pine is a big tree!
</td></tr>
</table>
Note that the syntax of using the $treeFarm context attribute reference is identical to the $treeList variable reference examined earlier.
Initializing the template engine
Examine the main() method listing of the VelocityParser class (see Listing 13). VelocityParser's constructor creates the parser and loads the template, then attributes to be used by the template engine are added, and finally processTemplate() is called to merge the data and template. We will examine each of these methods in turn.
You can use the static methods in the org.apache.velocity.app.Velocity class to initialize Velocity and load a template file. The methods to use are init() and getTemplate(), respectively. The call to the init() method occurs within the constructor of our VelocityParser class, as shown in Listing 16:
Listing 16. Initializing the template engine in the constructor of our VelocityParser class
public VelocityParser(String templateFile) {
try {
Velocity.init("velocity.properties");
mainTemplate = Velocity.getTemplate(templateFile);
}
catch( Exception ex ) {
System.out.println("Error processing template file: " + templateFile );
}
}
In Listing 16, the call to init() creates a single instance of the Velocity engine. If your application needs to create and manage multiple instances of the Velocity template engine, use the org.apache.velocity.app.VelocityEngine class instead.
Context chaining
An immediately usable Velocity context is created by simply calling the trivial constructor of the org.apache.velocity.VelocityContext class.
Velocity context can be chained (wrapped one inside another). This can be quite useful when you want to control the visibility or availability of certain object references in templates.
Velocity will search the attributes of all the chained contexts for object references. If there are duplicate names, the outer-most attribute will be used, and the inner attribute(s) with the same name will not be accessible.
To chain Velocity contexts, the context to be chained is passed as an argument to the constructor of a new context. The overloaded addToContext() method in our VelocityParser class, shown in Listing 17, illustrates this:
Listing 17. Adding context attribute or context chaining with the addToContext() method
public void addToContext(String key, Object value) {
if (mainContext == null)
mainContext = new VelocityContext();
mainContext.put(key, value);
}
public void addToContext(VelocityContext chainCtx) {
mainContext = new VelocityContext(chainCtx);
}
In the processTemplate() method, the template's merge() method is called to combine the context information with the template and generate the output stream, as illustrated in Listing 18:
Listing 18. Merging templates in the processTemplate() method
public void processTemplate() {
try {
BufferedWriter writer = writer = new BufferedWriter(
new OutputStreamWriter(System.out));
if ( mainTemplate != null)
mainTemplate.merge(mainContext, writer);
writer.flush();
writer.close();
}
catch( Exception ex ) {
ex.printStackTrace();
}
}
Tutorial Pages:
» Client and server-side templating with Velocity
» Basic template engine operation
» Velocity contexts
» Velocity as a standalone parser
» Velocity vs. JSP technology on the server
» Deploying Velocity with Tomcat 5
» Interoperating with the Struts framework
» Conclusions
» Resources
First published by IBM developerWorks
