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.
Repository
Repository
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.txtwhere
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.