Template Engines Supported By Niggle


Download:

Latest Version of Niggle (1.1 pre14)
(If you are starting with Niggle, get this one.)

Last Niggle 1.0.x release (1.06)

Forum example (requires Niggle 1.1)



Read More:

Niggle Home

Niggle Design Goals

History and current status

Generated Javadoc

Configuring XML-based Metadata

Subclassing ServletInteraction


Other Links:

Niggle Project Page on Sourceforge

Subscribe to Niggle mailing lists

Preamble

Using some kind of page template solution is really an absolute necessity in serious web application development, since outputting HTML via println() statements in your java code is really not a maintainable practice. I don't think I should launch into a sermon as to why this is so. If you've been there, done that, then you already know this, and if you haven't, then it is wise to believe those who have gone there before you! The Niggle framework currently gives you the choice of three popular open-source template engines: Freemarker, WebMacro, and Velocity. As you may know from reading the history of the Niggle project, Niggle began by leveraging Freemarker. Support for WebMacro and Velocity was introduced fairly recently.

What Niggle offers above and beyond any of these template solutions alone is a prebuilt solution for modeling your application's persistent data externally, as well as exposing the data to a page template and reading data from an HTML form. By separating out the persistence layer as well as presentation, Niggle offers the skeletal basis for developing web applications that roughly follow the much-vaunted MVC (model-view-controller) pattern. (And if you don't know quite what that is, well, just think of it as a synonym for GOODtm)

Configuring your Template Engine

In your deployment descriptor (that's a fancy term that means the WEB-INF/web.xml file) you can configure a servlet initialization parameter called PAGE_FACTORY_CLASS. If you intend to use Freemarker, this does not need to be set, since Freemarker is the default. If you intend to use WebMacro or Velocity, you do have to set this parameter. Within your servlet configuration, you would need something like:

  <init-param>
    <param-name>PAGE_FACTORY_CLASS</param-name>
    <param-value>webmacro</param-value>
  </init-param>
  

Note that "webmacro" above is a convenient shorthand that the code that processes the parameters understands to mean org.niggle.templates.webmacroimpl.WebMacroPageFactory. Similarly, if you put "velocity" above instead of "webmacro" that is a shorthand for org.niggle.templates.velocityimpl.VelocityPageFactory. If you write your own PageFactory implementation and wish to specify it in the configuration file, you will have to use the fully qualified class name. If you want to send parameters specifically to the webmacro or velocity template engines, you can do so in your deployment descriptor by defining init params (just like above) that are prefixed with org.webmacro. or with jakarta.velocity. respectively.

By default, it will be assumed that you wish to load templates relative to the classloader's CLASSPATH. This is the scheme that will allow you to put all of your .class files and associated resources in a .war archive. (This is also GOODTM) However, if you want your templates loaded relative to an absolute location on the file system, you can specify the init parameter RESOURCE_BASE, which specifies a location from which to load the templates. If this is an absolute path, this is assumed to be on the file system. If it is a relative path, then it is assumed to be relative to the classloader. For final deployment, it is far better not to specify an absolute path here, since a relative path (or nothing specified at all) means that your webapp will simply obtain the template files relative to the classloader. This is the most robust, portable solution. However, in a development stage, it may be useful to specify an absolute path here, which points to where your templates are on the file system.

Differences between using Freemarker and WebMacro or Velocity

Under the hood, Freemarker and WebMacro/Velocity actually take very different approaches to exposing objects to a page template. The Freemarker library defines three basic interfaces for objects that will be exposed to a page. Any object exposed to a page must implement at least one of these three interfaces:

  • freemarker.template.TemplateScalarModel
  • freemarker.template.TemplateSequenceModel
  • freemarker.template.TemplateHashModel

The freemarker engine parses your page template and compiles it into a tree. When it finally outputs the page, it traverses the tree and fills in the elements of the tree based on the variables in your data model. For example, if you have the variable ${foo.bar} in your page template, the template engine expects your root data model to contain a variable called "foo" and it requires that this variable be interpretable as a hash variable. From the engine's point of view, this means that the object implements the TemplateHashModel interface.

Of course, you may have noticed that the Niggle example code makes no reference to TemplateHashModel or any of these interfaces. Also, you can expose a data record onto a freemarker template directly and it gets interpreted as a hash, even though the org.oreodata.Record interface does not inherit from freemarker.template.TemplateHashModel. The reason this works is that Niggle transparently creates a wrapper object that does implement the right interface. In fact, the wrapper object that is used by default is org.niggle.templates.freemarkerimpl.RecordWrapper. And this object does implement TemplateHashModel. So, what Niggle does behind the scenes, when you expose a Record to a page, is that it actually creates one of these wrapper objects and exposes it. An interesting possibility that you have when you use Freemarker with Niggle (that is unavailable if you use WebMacro or Velocity) is that you can define your own subclass of RecordWrapper so that certain extra subvariables get exposed. Or conversely, you could actually override the get() method in your RecordWrapper subclass so as to hide or veto certain values from the page template layer. You specify a custom presentation wrapper for a Record type by using the PRESENTATION_CLASS attribute when you define a record in your recorddefs.xml. If you are using WebMacro, this attribute is not used.

By contrast, both WebMacro and Velocity are much more based on java's introspection capabilities. If you have the webmacro variable $foo.bar in a page, WebMacro and Velocity (like Freemarker does) assume that you exposed a variable called "foo" to your root context. However, it takes the reflective lookup approach to deducing what the "bar" subvariable is. It will look for either a getBar() method (javabeans style) or a get(Object obj) method to which it can pass the string "bar" in that order.

In fact, one thing that WebMacro and Velocity allow for that Freemarker simply does not, is arbitrary calls to public methods by name from a page template. I will not hide from you that I consider this to be rather dangerous. I am still not absolutely sure that this is evil by nature, or merely has the potential for evil. Still, it is possible that, ultimately, this capability is intrinsically evil, in the same way as the rings of power in the Tolkein books. Now, even given that, it is surely not as evil as the ability to embed arbitrary java code in a JSP template. But certainly, it does create the potential for people working on the page design layer to rely on the existence of arbitrary methods in your core java objects. This can create an undesirable coupling, where, whenever you want to refactor your java code, you have to verify whether a method that you wish to eliminate or rename is actually used somehow in a page template. And in fact, given the ability for variable aliasing that page templates provide, it could be fairly difficult to know for sure whether a method is being used.

Summary

You can use either Freemarker, WebMacro or Velocity in conjunction with Niggle. Freemarker is the default; it works well and the freemarker bridge code has been subject to much more usage and testing. Broadly speaking, you can use either one almost indistinctly as a java programmer, since they are wrapped up in a higher level API. The biggest difference will naturally be at the page template level, since the template languages differ significantly.

Probably, the biggest practical consideration in choosing which one to use will be whether the people working at the page design level already have experience with one or the other, or have a stated preference. If there is no stated preference, typically because your designers have used neither one, you might as well go with the default, which is Freemarker.

In the above, I point out a couple of basic differences. First of all, if you use the Freemarker bridge code, you have the possibility of implementing your own custom subclass of RecordWrapper. This can give you an extra degree of freedom when it comes to migrating your java code, without having to change any template code. On the other hand, the reflection-based approach of WebMacro or Velocity is appealing in certain ways, since it gives you access to arbitrary java methods from your page template. Though, you will note that I express my reservations about in that above.

Since it is not terribly difficult to write the bridge code that allows Niggle to work with other page template solutions, I anticipate that Niggle will at some point offer a greater choice of presentation solutions than it does now. Probably something that uses XML/XSL as well as a solution that uses JSP taglibs. Since XSL and JSP are standard, "approved" ways of doing things, there will likely be a fair bit of third-party tool support coming on line.

Additional Note

Since writing the text above, I have become the maintainer and lead developer of the FreeMarker project. I suppose that people would infer that, in terms of tight integration with Niggle, that FreeMarker will receive a kind of favoritism.

The above inference is correct. There has now been a release of FreeMarker version 2.1. The 2.1 final is about a week away. I will make no bones about the fact that I consider this to be a far superior solution to both Velocity and WebMacro at this juncture. Also, one should take into account that, since FreeMarker is being maintained by me as well, in all likelihood, the integration of Niggle and FreeMarker will be superior to the integration with Velocity or WebMacro.I have deprecated Velocity support (though it still works and is present) because the current distribution includes a Velocity->FreeMarker template converter.


This is a first draft of a document explaining Niggle's template engine support. If you note any inaccuracies in this document, or have any suggestions for improvement, please write me! I do not document the syntax of the template languages here. At some point soon, I anticipate including a quick-start crib sheet that explains the template language syntax of Freemarker, WebMacro and Velocity, and their usage with Niggle. Currently, for this information, please refer to the respective websites: freemarker.sourceforge.net, www.webmacro.org, and jakarta.apache.org/velocity.

Jonathan Revusky Last modified: 10 May 2002

Sourceforge Logo