Editing Resources in Maven with GMaven and Groovy Templates

In this post, I will show how to build a simple yet robust resource modification engine for Maven using GMaven and Groovy Templates.

We sometimes need to generate files in our build cycle that are specific to each server and change per deployment cycle. For some projects, this might be Flash / Flex actionscript files that need to reference the build server. For others, it might be datasource locations that change per build project. While maven provides a built-in resource filtering mechanism, it is tied to parts of the maven lifecycle that might not work well for all projects, and mostly changes resources for War files.

Groovy provides a very robust Templating engine. With the introduction of the GMaven plugin, it becomes possible to filter and re-write resource files using this robust mechanism. Combined with the power of Maven’s built-in profiles mechanism, this solution provides a robust and powerful way to edit Flex / Grails and other resources.

For our project, we needed to generate an actionscript file that tells our Flash files which server to connect to. Of course, this changes in every deployment location, and we needed a way to manage this. A naive way would be to check out the files from SVN and then modify them, but this can lead to unmodified errors and all sorts of issues. Ideally, we wanted it added to our maven buildcycle.

Here is our solution:

1. Add template handling to our Maven pom file.

We created a goal in Gmaven that processes templates within our build-templates directory. This can be overwritten in any build.

<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<executions>
<execution>
<id>filter-as-files</id>
<phase>validate</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<defaults>
<server.url>${appserver}</server.url>
<templateDir>build-templates</templateDir>
</defaults>
<source>
// import the simpleTemplateEngine class
import groovy.text.SimpleTemplateEngine

// get the templates directory

def templates = new File( project.basedir, project.properties['templateDir'] )
def engine = new SimpleTemplateEngine()

// in here, we are binding all the variables that will be replaced in our template files

def binding = [‘server_url’ : project.properties['server.url']]

// iterate through each file of the templates folder

templates.eachFile{ file ->

// bind variables

def template = engine.createTemplate(file).make(binding)

// the first line in the template tells me where the destination is

def destination = file.readLines()[0].split(“destination:”)[1]

// define and write destination

def toFile = new File( project.basedir, destination + File.separator + file.name )
toFile.write( template.toString() )
}
</source>
</configuration>
</execution>
</plugin>

Notice that we have a defaults section here that points to profile variables in our profiles. These values are then passed to our profiles via this line of code.

 def binding = ['server_url' : project.properties['server.url']]

You can add more variables to be bound. We had to rename our variable so that Groovy wouldn’t try to access the url variable of the server project when defining the template.

project.properties[ ] is the syntax to access Maven properties used by GMaven, read more here

2. Create different profiles for maven

Refer to Maven Profiles for more info on how these works.

We can then define a separate user profile file in Maven to allow for different test / deploy / development environments. They can also be defined externally in Maven

<profiles>
<profile>
<id>localhost</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<appserver>http://localhost:8080/</appserver&gt;
</properties>
</profile>
<profile>
<id>hudson</id>
<properties>
<appserver>http://hudson.testserver.myrobustapp:8180/</appserver&gt;
</properties>
</profile>
<profile>
<id>deployment</id>
<properties>
<appserver>http://www.myserver.com/</appserver&gt;
</properties>
</profile>
<profile>
<id>morph</id>
<properties>
<appserver>http://something.mor.ph/</appserver&gt;
</properties>
</profile>
</profiles>

Notice how we can define a activeByDefault profile so that if a profile is not specified, we can still generate files with default values.

3. define our template files.

A template file is simply a delimited groovy string ( i.e. // for / ) that lives inside the build-templates folder. Any parameter that needs to be replaced will be in the form $server_url, which is defined within the binding part of the pom file.

For example, we created a file Environment.as used by our Flex files to refer to this server, this file will go into the build-templates directory and look like this:

// destination:src/main/flex/
// defines a deployment environment for ActionScript file

package
{
public class EnvironmentVars
{
public static const SERVER_URL : String = “$server_url”;
}
}

When we build our file in maven, the $server_url parameter will be replaced by our variable, and the result will be written to the destination directory specified.

4. call different profiles for builds

To run this, we call

mvn validate
mvn -Phudson validate
mvn -Pmorph validate

which will change the templates . We had to use the validate lifecycle due to some other dependencies, but this can be changed in your plugin’s <phase> definition.

You can see how this can also be used to define different datasources or inject the server name in the Grails config file.

About these ads

One thought on “Editing Resources in Maven with GMaven and Groovy Templates

  1. Pingback: Nine Lessons from building a Grails / Flex / Flash website « Dump brain here : Flex, AIR, Grails, Groovy, Facebook and all that jazz

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