Using Groovy Templates and Filters Java

I have written about the Groovy language a few times. It is a wonderful language and integrates seamlessly with Java. Recently, I have found that it can be very useful for templates and filters.

Using Groovy for Filtering

Consider an application where there are many events that fire on certain conditions. The Observer pattern is often used for these types of event handlers. Also consider that the user (not the developer) wants to restrict or filter out events so only the ones they want are fired by the handler. Essentially the user needs a filter language where they can express their business rules. This filter needs to exist outside of the regular codebase so the user can change it on the fly.

Groovy solves this problem very neatly. Consider an Event class with the following properties:

  • severity
  • timesCalled
  • message

Assume that an instance of this class is provided as the object ‘e’. In groovy we could express a filter script that takes events with a severity less than 2 or times called greater than 5 as the following:


e.severity < 2 || e.timesCalled > 5

The above script is pretty simple and is easily written by a technical savvy user. I have written a simple helper class that facilitates creating reusable scripts like our filter script. Here is the code:


public class ReusableScript {
    private GroovyClassLoader gcl = new GroovyClassLoader(getClass().getClassLoader());
    private Class scriptClass = null;
    
    public void setScriptString(String scriptString) throws UnsupportedEncodingException {
        if (scriptString == null || scriptString.trim().equals("")) {
            return;
        }
        InputStream in = new ByteArrayInputStream(scriptString.getBytes("UTF-8"));
        scriptClass = gcl.parseClass(new GroovyCodeSource(in, "Filter", ""));
    }
    
    public Script newScript() throws Exception {
        if (scriptClass == null) {
            return null;
        }
        return (Script) scriptClass.newInstance();
    }
}

To use this script to actually execute the filter, you would do something like this:


// Creating the filter script. Assumes filterString is set by the user (I use spring for this)
ReusableScript filter = new ReusableScript();
filter.setScriptString(filterString);

// Typically this code would be running in the event handler. Assumes that an object e is available that is the event
filterScript = filter.newScript();
// Bind the 'e' object into the binding context of the script
filterScript.setProperty("e", e);
Object result = filterScript.run();
if (result instanceof Boolean && ((Boolean) result).booleanValue() == true) {
    // The filter has passed.
    // ... Code that performs the operation
}

Very little code is actually needed to put this together. The ReusableScript class can be used many times. The groovy code is only compiled once so performance is very good.

Using Groovy for Templating

A similar problem is the problem of templating. Consider an application that sends emails on error conditions. The user may wish to customize the email message that is sent out. They also may want to be able to use information from the application to provide meaning to the message. There are many template and expression languages available for Java. I have looked at using Apache Commons EL and Velocity. My main complaint on these languages is their complexity. It requires learning a new language syntax and integrating them often requires quite a bit of code. Let’s consider a more groovy solution.

Using the same ReusableScript class as used for filtering, we can provide templating. Consider a data class called Event that contains the following properties:

  • message
  • detail
  • hostname

Consider the following Groovy script that creates the body of an email message:


"""[$e.hostname] An error occurred: $e.reason

$e.detail
"""

This may produce a message that looks like this:

[localhost] An error occurred: File not found: abc.txt

FileNotFoundException ...

This is essentially making use of Groovy’s Templates that are built in to the language. The template engine can be used by itself standalone, but this provides a simpler integration. The other benefit is the if more complicated logic is required beyond a simple template, actual groovy code can be written beyond the simple script. The script is a full groovy script and would allow you to essentially do anything from it.

The template script would be loaded the same way as our previous filter script. This time instead of evaluating the script as a boolean, we get it as a string.


// ... Setup of filter script ...

Object result = filterScript.run();
if (result instanceof String) {
    // Code that uses the string
}

So that is two easy ways the Groovy can be used in a Java application to solve some of these simple problems.