Ant transforms using Groovy template scriptdef

Ant provides powerful transformation capability. For example, the copy task can include filters that replace tokens in the text. There is also the XSLT task to perform more complex XML based transforms.

Sometimes you may need more dynamic or procedural transforms for non-xml based templates. While this can be done in Ant, they should not be; Ant should really only be used in a declarative manner. One can do this outside of Ant using custom solutions or use the various templating frameworks, such as Velocity and Freemarker, which provide Ant plugins.

Another alternative is the Groovy language which has always provided text processing in the form of GStrings and templates. These are used in various solutions such as Groovlets and Groovy Server Pages. Below I show how Groovy templates can be easily used in Ant.

listing 1 shows a meeting agenda text template with a list of topics. Note that it has a GString interpolated string using “$” character. It also, analogous to Java Server Pages, uses a scriptlet with <% and %> to execute code. Yes I know, scriptlets are evil.

List 1, template1.txt, a template:

Hello ${name}!
Agenda is:
<% 
   subject.split(',').each{
%>- $it 
<% }	
%>

In listing 2 below, an Ant script invokes the “template” task to transform the template in listing 1.

Listing 2, build.xml, use template task:

<project default="init">
	
<import file="tasks.xml"/>
	
<target name="init" 
  xmlns:jb="https://josefbetancourt.wordpress.com">
  <jb:template 
	src="template1.txt" 
	dest="temp.txt" 
	property="result" 
	failOnError="true">
		
	<property name="name"    
		value="world"/>
	<property name="subject" 
		value="beans,GStrings,templates"/>
		
  </jb:template>
	
  <echo>${result}</echo>
	
</target>	
</project>

Listing 3 shows an example run.

Listing 3, example use:

init:
Saving result to temp.txt
     [echo] Hello world!
     [echo]     Agenda is:
     [echo]     - beans
     [echo]     - GStrings
     [echo]     - templates
     [echo]

BUILD SUCCESSFUL

Listing 4 is the implementation. It is a simple scriptdef using Groovy as the script language. The Groovy code is inline but could have been in external file using the “src” attribute of the scriptdef declaration.

Listing 4, tasks.xml, the scriptdef implementation:

<project>
<!-- config stuff not shown -->

<!--
Render a Groovy template using properties to create the binding 
 -->	
<scriptdef name="template" 
  language="Groovy" 
  classpathref="groovy.lib" 
  uri="https://josefbetancourt.wordpress.com">
	
  <attribute name="src"/>   <!--  required -->
  <attribute name="dest"/>  <!--  optional -->
  <attribute name="property"/> <!--  optional -->
  <attribute name="failOnError"/> <!--  optional, true -->
  <element name="property" type="property"/> <!--  required -->
	
<![CDATA[
def SRC= 'src';
def PROPERTY = 'property'
def DEST = 'dest'
def FAILONERROR = 'failonerror'
		
try{
	// convert element properties to map
	def map = [:]
	elements.get(PROPERTY).each{
		map.put(it.name,it.value)
	}
			
	// render the template
	String result = new groovy.text.GStringTemplateEngine()
	  .createTemplate(new File(attributes.get(SRC))
	  .getText())
	  .make(map).toString()
	
	def prop = attributes.get(PROPERTY)
	if(prop){ // save to property?
		project.setNewProperty(prop, result)
	}
		
	def dest = attributes.get(DEST)
	if(dest){ // write to file?
		project.log("Saving to $dest",project.MSG_INFO)
		new File(dest).write(result)
	}
}catch(Exception ex){
	def f = attributes.get(FAILONERROR)
	def failOnError = f ? f : true;

	if(failOnError == 'true'){
		throw ex;
	}		
}			
]]>
</scriptdef>  <!-- end name="template" -->

</project>

Summary
Shown was an example of using Groovy templates in an Ant task. A simple scriptdef was created to allow reuse in Ant scripts.

Extensions
Kind of begs the question, since scriptlets have a bad rep, should there instead be a way of using taglibs in the templates. I think Grails implemented Groovy taglibs.

References

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: