03 August 2007

Tags: freemarker groovy

After finding out that Groovy templates would be great as a replacement for Velocity, then thinking about security issues, I came to a third solution.

FreeMarker for Groovy

Some of you told me that I could take a look at FreeMarker, as a practical replacement for Velocity. I went on, but seen nothing that would fit my needs : beeing able to dynamically add tags'' or plugins'' to a customer template. I mean I would not need to rebuild and redeploy an application just to get a simple plugin working. Then I thought I would be able to create a transform for FreeMarker that would make the benefits of the FreeMarker template engine available for Groovy. Basically, it would fit my needs :

  • Beeing able to dynamically add plugins for a customer

  • fix does nasty security issues by making the web designer unable to directly write Groovy code (the programmer creates plugins, then makes them available to a customer)

How does it work ?

Imagine your customer requires an URL Encoding text transform, and that FreeMarker does not offer this possibility. Then, you would just need to :

  • Create a plugin named urlencoder that implements the IGroovyFreeMarkerPlugin interface

  • Copy this plugin into the Groovy FreeMarker template engine plugins directory

Tell your customer how to use it :

<@groovy plugin="urlencoder">this is an expression that will be converted to its URL Encoding form

The FreeMarker engine will then call your plugin and return the transform. Note that you may embed FreeMarker tags and variables : the transform content does not need to be plain text. For example :

<@groovy plugin="urlencoder">this is an ${expression} that will be converted to its URL Encoding form

Now take a look a the plugin code itself:

import groovy.text.freemarker.IGroovyFreeMarkerPlugin

class urlencoder implements IGroovyFreeMarkerPlugin {
 String transform(Map params, String content) {
  URLEncoder.encode(content);
 }
}

Here’s a sample groovy script that will show you how you can use the template engine :

import groovy.text.freemarker.FreeMarkerTemplateEngine

def tpl = '''
Hello, ${user.name}
<@groovy plugin="urlencoder" mode=user>this is a test ${user.name}'''
def engine = new FreeMarkerTemplateEngine("plugins")
def binding = ["user" : ["name":"cedric"]]
println engine.createTemplate(tpl).make(binding)

Default implementation bonuses

I’ve built a rather simple implementation, but it still has some additional features:

  • Template caching: instead of using the createTemplate() method, use the createNamedTemplate() one first. It will create a template and put it into the template cache, then use the getNamedTemplate() method to retrieve a cached template.

  • Plugin loader: there’s a default implementation which reads plugins from a directory. Feel free to implement the IGroovyFreeMarkerPluginLoader if you want more complex loaders

  • Plugin parameters: if the <@groovy> tag content is not sufficient, you may add parameters to the transform, and use them in the plugin thanks to the params map. For example : <@groovy plugin=temperatureconvertor'' source=celcius'' dest=``kelvin''>112

Grabbing the code

You will also need the latest freemarker.jar. I will not have much time to work on this, so feel free to contribute !