Wednesday, July 16, 2008

Writing Groovy Server Pages output to a file (or to any Writer)

One thing I've never managed to do is to write a JSP page to a file or to any stream other than the http response output. That's something that can be useful for example, to generate HTML files in batch, using JSP files as templates. Due to that, I've turned to use Velocity instead of JSP in my past days.


But now, with Grails I use Groovy Server Pages (or GSP, in short). I like GSP a lot, and recently I needed to write the output of one of my GSP pages to a file. The Groovy Pages Template Engine is a Groovy Template Engine that automatically binds the http request attributes when the template result is generated. So, in order to use my GSP as a template outside Grails, I just need to use a Mock HttpRequest to pass the referenced variables. After a couple of tries, here's the code that got things done. All the needed libraries are in the dist and lib folders of the Grails installation folder:


test.gsp


<html>
<body>
<ul>
<g:each in="${theList}">
<li>${it}</li>
</g:each>
</ul>
</body>
</html>

GspToFileTest.groovy


class GspToFileTest{

static void main(args) {
MockHttpServletRequest servletRequest = new MockHttpServletRequest()
List theList = ['one','two','three']
servletRequest.setAttribute('theList', theList)
GrailsWebRequest grailsWebRequest = new GrailsWebRequest(
servletRequest,new MockHttpServletResponse(),
new MockServletContext())
grailsWebRequest.setAttribute(
GrailsApplicationAttributes.WEB_REQUEST
, grailsWebRequest, 0)
RequestContextHolder.requestAttributes = grailsWebRequest
GroovyPagesTemplateEngine engine = new GroovyPagesTemplateEngine()
Resource page = new FileSystemResource('test.gsp')
Writer writer = new PrintWriter('test.html')
engine.createTemplate(page).make().writeTo(writer);
writer.close()
}

}

And, the result HTML is...


test.html


<html>
<body>
<ul>

<li>one</li>

<li>two</li>

<li>three</li>

</ul>
</body>
</html>

A Groovy way to generate delegate methods

To generate delegate methods When working with Java in Eclipse, you simply go to Source->Generate Delegate Methods and voila. For example, when implementing a decorator:



public Class MyDecorator extends SuperClass {
private SuperClass decorated;

void someMethod() {
this.decorated.someMethod();
}
void otherMethod() {
this.decorated.otherMethod();
}
void andAnotherMethod() {
this.decorated.andAnotherMethod();
}
void anotherMoreMethod() {
this.decorated.anotherMoreMethod();
}
}

This can be a really tedious task if there's many methods and you aren't working with an IDE. Well, here's another reason to love Groovy. Simply use missingMethod to invoke the corresponding decorated class method when a method call fails on the decorator class:



class MyDecorator {
SuperClass decorated

def methodMissing(String name, args) {
decorated.invokeMethod(name,args)
}
}

Now, if you for example call myDecorator.otherMethod() the call will fail cause otherMethod is
not declared in MyDecorator, then a call to methodMissing is triggered, invoking the corresponding method in the decorated object