dcsimg

Velocity Picks up Speed

Some of the most exciting projects in Java are intended for Web servers, where Java applications can deliver dynamic Web content, store, retrieve, and display database information, and execute Java code embedded in Web pages. The opportunity to write some of these Web applications, called servlets, is one of the best reasons to learn the Java language.

Some of the most exciting projects in Java are intended for Web servers, where Java applications can deliver dynamic Web content, store, retrieve, and display database information, and execute Java code embedded in Web pages. The opportunity to write some of these Web applications, called servlets, is one of the best reasons to learn the Java language.

While Java is great for programmer productivity, using Java for Web applications poses a challenge for the Web site development team as a whole: how can Web designers and Java programmers work together and not clobber each other? When a site is being developed, it’s rare for the same people to create the content and appearance of the site and handle the programming.

Many Web site development projects choose to use Java Server Pages (JSP), a component of Java’s servlet technology, to place Java code on a Web page alongside HTML or XHTML markup. Using JSP, the embedded Java code is executed by the Web server when the page is requested by a client, and produces HTML or XHTML that’s woven seamlessly into the transmitted page.

JSP code is Java, making it easy to learn. Here’s a simple JSP example that uses a for loop to display an array of objects on a Web page:


<p>Customers:
<%
for (int i = 0; i < 3; i++) {
%>
<p><%= cust[i].name %>
<p><%= cust[i].address %>
<p><%= cust[i].city %> <%= cust[i].state %> <%= cust[i].zip %>
<% if (cust[i].current) { %>
<p><i>Current customer</i>
<% } %>
<p>
<%
}
%>


This JSP code can produce HTML markup such as the following:
<p>Customers:
<p>Edward Quartermaine
<p>66 Harbor View Rd.
<p>Port Charles, NY 10019
<p><i>Current customer</i>
<p>
<p>Ned Ashton
<p>321 Harbor View Rd.
<p>Port Charles, NY 10019
<p>
<p>Laura Spencer
<p>24 Royal St.
<p>Port Charles, NY 10019

While Java Server Pages are an easy (and popular) way to incorporate Java into Web presentation, there’s little separation between Web content and the code used to produce it. (The same is true of Web applications created using the server-side scripting language PHP, which also mixes programming and Web content together.) Using JSP (or PHP), it’s easy to get in the habit of putting programming logic on a Web page among the images, markup tags, and text, rather than squirreling it away in a place that’s not quite so easy to “hose” (such as a read-only Java class file).

Another way to mix Web content and code is to use Velocity, a general-purpose template rendering engine offered by Jakarta, the open source Java project of the Apache Software Foundation. Jakarta, best known for its Tomcat Web server and Ant build tool, includes more than a dozen Java projects. This past August, this column covered log4j, Jakarta’s robust logging API (available online at http://www.linux-mag.com/2002-08/java_01.html). Coming up in March 2003, the magazine will cover Struts, Jakarta’s framework for Web applications.

Jakarta recently (as of July 24, 2002) posted the second release candidate of Velocity 1.3.1, which works with several versions of Java 2, and requires the Ant build tool. You can read about the origins of the Velocity project and download the code from the Jakarta Web site at http://jakarta.apache.org.

Template for Going Fast

Velocity was first released in August 2000, and was developed by Jason van Zyl, Daniel Rall, and Jon Stevens to address a glaring concern they had with JSP — programming and presentation were too closely intertwined.

Velocity is a Java class library for rendering data within an application. Using the technology, the contents of a template file are merged with data contained in Java objects. Output is described with the Velocity Template Language, a simple set of object references and programming directives.

A Velocity template can be used to produce a Web page, an e-mail message, an XML file, and many other document and output formats. Another “killer app” for Velocity is a mail merge, an application that pulls addresses out of a database and produces a business mailing. However, Velocity’s most common use, according to its developers, is to render content for Java servlets in Web applications.

Unlike Java Server Pages, Velocity does not include Java statements in templates. Instead, the intended use of the template engine is to present existing data — so, by design, the Velocity Template Language does not offer a means to create new objects. As a result, Velocity mirrors the model-view-controller paradigm (MVC), a programming methodology that separates data presentation and user input (the view) from data (the model) and code that operates on it (the controller).

Every Velocity project requires the creation of one or more templates. A template is a text file containing static content, references to Java objects, and directives that execute control structures such as loops. Templates can be created with vi or any other text editor.

Here’s a short sample template saved as text file greeting.vt:


Greetings, $name.

#foreach( $game in $gameList )
$game.title
#end

How about a nice game of $favorite?

A Velocity template contains static data, such as the text How about a nice game of, and dynamic data that looks like variable names, such as $favorite. Dynamic elements are preceded by a $ character if they are object references, and a # character if they’re directives (directives are commands that tell the Velocity template engine to do something). The greeting.vt template contains five references: $name, $game, $gameList, $game.title, and $favorite. It also includes two directives: #foreach and #end.

Velocity accomplishes its work through the interaction of three objects: an engine, a template, and a context. The engine object (VelocityEngine) merges a template object (Template) with data contained in a context object (VelocityContext). (All of these classes belong to the org.apache .velocity and org.apache.velocity.app packages.)

The end result is an object that holds the merged output. And rather than reinvent the wheel, Velocity uses one of the Writer classes in the java.io package to hold the output.

Starting the Engine

A VelocityEngine object is created and initialized by calling new() and then the new object’s init() method, as in the following example:


VelocityEngine engine = new VelocityEngine();
engine.init();

A Template object is produced by calling the engine’s getTemplate() method with the name of a template file:


Template base =
engine.getTemplate(“greeting.vt”);

A VelocityContext object is created simply by calling its constructor:


VelocityContext data =
new VelocityContext();

The context object holds all of the data required by the template. Context data can be represented by objects of several forms, including Lists, Maps, and Strings.

To store data, call the context object’s put() method with two arguments: the object’s name, and an object that represents its value. The easiest way to associate data with template references is to store it under the same name with the $ removed.

For example, the following statements create data for two of the object references in the greeting.vt template shown on the previous page: $name and $favorite:


data.put(“name”, “Professor Falken”);
data.put(“favorite”, “chess”);

When the template is merged with the context object’s data, the $name and $favorite references in the template are replaced with the string representation of the objects associated with those names. In this example, the objects are strings, so the output will be Professor Falken and chess.

A Velocity template can also access any public method of an object stored in a context. This makes it possible to refer to objects of existing classes — even if they weren’t created with Velocity in mind — as long as they already produce the output you need for the template. Object references in a template can also be followed with periods to retrieve object data using the object’s own methods.

For example, if you put this line in the greeting.vt template:


The word C<$favorite> is C<$favorite.length()> characters long.

It would produce the following output when the template is rendered:


The word “chess” is 5 characters long.

The same technique also can be used to refer to objects inside of objects. Velocity uses Java introspection to find and display a string representation of the enclosed object.

For example, in greeting.vt, $game refers to a Map. The reference to $game.title causes the Velocity engine to call the map’s get(“title”) method, returning the associated object as a string.

This capability is extremely flexible. If $game referred to an object that was not a map, the reference to $game.title would still work as long as the object had a getTitle() method. JavaBeans programmers ought to be comfortable with this feature, since it mimics the functionality of an integrated development environments that support bean retrieve object data using the object’s own methods.

The Velocity Template Language also includes a small number of directives: #foreach(), #if(), #else, #elseif(), #set(), #macro(), #include(), #parse(), #end, #stop, ##, #*, and *#.

The VTL directive #foreach iterates through each value in a data structure. It can loop through Collection, Enumeration, Iterator, Map, or an array of objects. The #end directive marks the end of the body of the loop (#end serves a similar purpose for conditional directives).

The following Java code creates an array that contains the names of several games, and adds the array to a context object:


ArrayList gameList = new ArrayList();

HashMap item = new HashMap();
item.put(“title”, “chess”);
gameList.add(item);

item = new HashMap();
item.put(“title”, “checkers”);
gameList.add(item);

item = new HashMap();
item.put(“title”, “tic-tac-toe”);
gameList.add(item);

item = new HashMap();
item.put(“title”, “global thermonuclear war”);
gameList.add(item);

data.put(“gameList”, gameList);

The #set directive changes the value of an object, using the same $ references that display objects. For example, the following line could be used in greeting.vt to change $name:


#set($name = “David Lightman”)

The #if directive and other conditional directives work with the same operators as Java, and support booleans. Here’s an example:


#if($name == “David Lightman”)
I was expecting Professor Falken.
#else
Greetings, $name.
#end

The remaining VTL directives are used for comments, debugging, and other tasks:

  • ## denotes a single-line comment, and #* and *# are used around a multi-line comment. The rendering engine ignores comments in a template.
  • The #stop directive halts the rendering of a template at the #stop instruction, and is useful for debugging.
  • The #include and #parse directives incorporate an external file into a template, placing its contents at that spot in the template. However, the two directives work very differently. A file added with #parse can contain object references and directives that are parsed and processed as if they were a part of the file that included them. #include simply adds text to the template as-is without any such processing.
  • The #macro directive causes sophisticated preprocessing to take place within a template using function-like sections of VTL called “Velocimacros.”

Rev It Up

Once all of the necessary data has been added to a context object, it can be merged with a template. To merge a context object with a template object, call the template object’s merge() method with two arguments: the context object and an object that will hold the merged output. The latter object must be created from one of the Java Writer classes such as StringWriter. The following statements complete the current example:


StringWriter output = new StringWriter();
base.merge(data, output);
System.out.println(output);

Listing One contains Greeting, a complete, working Velocity example. Greeting imports the necessary packages and deals with ResourceNotFoundException, an exception thrown when a template’s text file cannot be found, and other exceptions the Velocity engine might generate. The output is shown in Figure One.




Listing One: The Greeting class, a simple Jakarta Velocity application


import org.apache.velocity.*;
import org.apache.velocity.app.*;
import org.apache.velocity.exception.*;
import java.io.*;
import java.util.*;

public class Greeting {
public static void main(String[] arguments) {
try {
// create the engine
VelocityEngine engine = new VelocityEngine();
engine.init();

// get a template
Template base = \ engine.getTemplate(“greeting.vt”);

// set up a data context
VelocityContext data = new VelocityContext();
data.put(“title”, “Professor Falken”);
data.put(“favorite”, “chess”);

ArrayList gameList = new ArrayList();
HashMap item = new HashMap();

item.put(“title”, “chess”);
gameList.add(item);

item = new HashMap();
item.put(“title”, “checkers”);
gameList.add(item);

item = new HashMap();
item.put(“title”, “tic-tac-toe”);
gameList.add(item);

item = new HashMap();
item.put(“name”, “global thermonuclear war”);
gameList.add(item);

data.put(“gameList”, gameList);

// produce and display the output
StringWriter output = new StringWriter();
base.merge(data, output);

System.out.println(output);

} catch (ResourceNotFoundException rnfe) {
System.out.println(“Resource error: ” \
+ rnfe.getMessage());
} catch (Exception e) {
System.out.println(“Error: ” + e.getMessage());
}
}
}




Figure One: The output of a merged template


Greetings, Professor Falken.

chess

checkers

tic-tac-toe

global thermonuclear war

How about a nice game of chess?

Green Light!

Velocity is an intriguing solution for projects that require programmers to be quarantined from the rest of a team, lest their code catch a few nasty bugs. The relatively small number of directives in the Velocity Template Language overcomes one of the biggest obstacles to its adoption: “YASL,” the requirement to learn “yet another scripting language.”

Like the Jakarta log4j project covered earlier this year, Velocity contains a core set of classes that can be put to use immediately. An indication of how useful Velocity can be is the number of other projects that make use of it, including the Struts and Turbine Web application frameworks (http://jakarta.apache.org), the Roller “blog” software (http://www.rollerweblogger.org/index.html), and the Maverick MVC framework (http://sourceforge.net/projects/mav).

Next month, Java Matters will cover XML-RPC, a remote procedure call protocol developed by Userland Software that Red Hat is employing to operate the Red Hat Network, its automated, remote system administration tool.



Rogers Cadenhead is a Web application developer and the coauthor of Teach Yourself Java 2 in 21 Days, Third Edition from Sams Publishing. Visit his weblog at http://workbench. cadenhead.info. Download the source code for this column from http://www.linux-mag.com/downloads/2002-12/java.

Comments are closed.