Template), the
repository (interface Repository) and the template cache (class
TemplateCache).
Template classTemplate class represents a template. One way to create a template instance is
to use its two-parameter constructor that takes a template string and a template name as parameters:
Template template = new Template (templateString, "myTemplate");
The template name (myTemplate in this example) is used when reporting errors, and assumes
significance when including templates within
other templates. The most significant Template method is expand, used to expand
the template into a Writer. For example:
template.expand (context, responseWriter);
The second parameter is a standard java.io.Writer instance into which output is written. The
first parameter provides data context for the template expansion. You would usually want this first
parameter to be a java.util.Map containing the data values used in the template
expansion. This Map can be arbitrarily complex in the sense that it can contain nested Maps, Lists,
arrays or other Java objects. The expand method wraps this Map into the Javascript
environment with simplified access.
The Template object represents a single template that does not know of the existence of
other templates. Therefore, you cannot use document.include in templates expanded by this
class. To enable such includes, you must use the cached template.
RepositoryRepository interface, is a collection of
template strings accessible by template name. One implementation of this interface is the
FileRepository class, which views the contents of files in the subtree rooted at a particular
directory as template strings, with accessible by file name. For instance, you would create a
FileRepository instance via
FileRepository fr = new FileRepository ("/web/templates");
Then fr would make all the files under /web/templates available via the
Repository interface.
TemplateCache object caches the templates available from a repository. Cached templates
are maintained in pre-parsed format, so that we only incur the parsing cost the first time a template is
accessed. The TemplateCache uses a lazy caching mechanism to ensure that, whenever the
template in the repository has been modified, the cached copy is automatically refreshed.
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import jstl.template.Template;
public class Example1 {
public static void main (String[] args) throws Exception {
// Create a template that is read in from System.in
Template t = new Template (new InputStreamReader (System.in));
// Expand it and write the result to System.out
t.expand (null, new OutputStreamWriter (System.out));
}
}
In this example, the first parameter to the expand method is null, so the template cannot
make any references to the templateContext object. Also note that, since this example does
not use a TemplateCache, the template cannot include any calls to document.include.
Here are the steps to execute this program:
Example1.java.jstl.jar and the Rhino jar file
rhino1_6R5_small.jar.
javac Example1.java
java Example1 < template1.txt
where template1.txt is any file you want to test as template code. You will see the
expanded template produced by the program.
TemplateCache
instance that will provide access to templates from the repository.
To initialize a templating system using files from the file tree rooted at /web/templates, we
would say:
TemplateCache cache = new TemplateCache (new FileRepository ("/web/templates"));
Subsequently, each time we need a template to expand, we would retrieve it from the cache and expand it
into a Writer, using a suitable template context:
Template template = cache.getTemplate (templateFileName);
Map templateContext = new HashMap();
// Set up templateContext with a suitable contents here....
template.expand (templateContext, outputWriter);
To illustrate these ideas, here is a complete program that uses the FileRepository and
TemplateCache classes.
import java.io.OutputStreamWriter;
import java.util.*;
import jstl.template.FileRepository;
import jstl.template.Template;
import jstl.template.TemplateCache;
public class Example2 {
public static void main (String[] args) throws Exception {
// Create a template cache that holds files in the current directory.
TemplateCache tc = new TemplateCache (new FileRepository ("."));
// Get a template from the cache.
Template t = tc.getTemplate (args[0]);
// Prepare a templateContext
Map aMap = _prepareContextMap ();
// Using the templateContext, expand the template to System.out
t.expand (aMap, new OutputStreamWriter (System.out));
}
private static Map _prepareContextMap () {
Map<String, Object> aMap = new HashMap<String, Object>();
aMap.put ("aString", "This is a string.");
aMap.put ("number", new Integer (433));
aMap.put ("aList", Arrays.asList (new Object[] {"Foo", 937, new Date()}));
aMap.put ("anArray", new Object[] {5, 13, new Date(), 11});
Map<String, Object> subMap = new HashMap<String, Object>();
aMap.put ("subMap", subMap);
subMap.put ("date", new Date());
return aMap;
}
}
TemplateCache class uses a “lazy cache” mechanism for caching. It
maintains a map whose keys are resource names from its repository, and the correspinding values are
pre-parsed Template instances. When a
client invokes the getTemplate method to request a Template instance, the
TemplateCache checks whether there is an entry in its map, and if so, whether the entry has a
modification date no later than that of the corresponding resource in the repository. If either of these
conditions fails, the TemplateCache refreshes the template from the repository and parses the
template again. This mechanism has several benefits:
document.include call causes template B to be automatically
recompiled. This contrasts with other template implementations such as JSP and Velocity, where you
would have to manually "touch" the including template A in order for you to see the effect of your change to
template B.
Timing.java
that is included in the examples directory of the JSTE distribution. You will find (on typical
hardware) that while the first-time cost of template expansion can be as high as 1.5 seconds,
subsequent template expansions are in the 10- to 20-millisecond range.