Register | Forgot password
Anyone doing serious builds with Maven will at some point have the need to have access to some kind of dynamic property in the build. Using a plugin that can be configured with Beanshell script may be an elegant solution.
The problem of static properties
Maven provides the concept op build time properties that can be used as parameters in the project object model. A typical use case for this is substituting placeholder in (re)sources.
By default the available properties are 1) hardcoded Maven project object model properties like pom.version, arbitrary Java system properties, developer defined properties in the pom.xml and user defined properties in the settings.xml. In addition for filtering property files can be configured in the pom.xml
Although this provides us with quite a few options the common denominator is that these are all static in the sense that the values are hardcoded.
But what if you want a property that has to be determined at runtime? If you want to access the buildtime you may use the ANT plugin. If you require access to the SVN version you may use the buildnumber plugin. And so on.. if you are an expert Google-r you'll find many plugins created by people that ran into the same problem at some point.
However, the problem here is that every time your build is getting more complex as you will need to maintain configuration and versioning of all these (untrusted) plugins.
Setting properties from a Mojo
If no plugin is available online you may create your own plugin that does exactly what you want. Once you know how to do this it is easy to create a special purpose plugin. A minimal version would look something like this:
/**
* @goal set-myproperty
*/
public class MyPropertyMojo extends AbstractMojo {
/**
* @parameter expression="${project}" required="true"
*/
private MavenProject mavenProject;
public void execute() throws MojoExecutionException, MojoFailureException {
final Properties projectProps = mavenProject.getProperties();
projectProps.put("mypropertykey" , "mypropertyvalue");
}
}
Once you have successfully compiled and installed this plugin you can use it in your build by configuring it in your pom. That would something like this:
<plugin> <groupId>nl.gx.webmanager.tools</groupId> <artifactId>webmanager-maven-plugin</artifactId> <executions> <execution> <id>setmyproperty</id> <phase>validate</phase> <goals> <goal>set-myproperty</goal> </goals> </execution> </executions> </plugin>
As a result you would be able to use this property for filtering resources where ${mypropertykey} will be substituted with "mypropertyvalue".
However, this strategy means that every time you need a dynamic property you need to create a new Mojo to help you out or.
Adding Beanshell in the mix
To get around this problem we need some way to allow users to configure dynamic properties by configuration in a generic way using just one plugin. This if where Beanshell enters the stage.
The basic idea is to create a Mojo that is configured to interpret its its configuration properties and add
them as project properties. A basic implementation is shown below.
/**
* @goal eval-bsh-props
*/
public class BshPropsMojo extends AbstractMojo {
/**
* Bsh Properties.
*
* @parameter
*/
private Properties bshProps;
/**
* @parameter expression="${project}" required="true"
*/
private MavenProject mavenProject;
public void execute() throws MojoExecutionException, MojoFailureException {
final Properties projectProps = mavenProject.getProperties();
Interpreter i = new Interpreter();
Iterator keys = bshProps.keySet().iterator();
while (keys.hasNext()) {
try {
String key = (String) keys.next();
i.eval((String) bshProps.get(key));
String value = (String) i.get(key);
projectProps.put(key , value);
} catch (EvalError e) {
getLog().error("Evalutation for bshProp failed: " + e.getCause());
e.printStackTrace();
}
}
}
}
Using this plugin to provide a quick and dirty solution for the use cases I mentioned before would be done by configuring the pom.xml as show below.
<plugin>
<groupId>nl.gx.webmanager.tools</groupId>
<artifactId>webmanager-maven-plugin</artifactId>
<executions>
<execution>
<id>setstuff</id>
<phase>validate</phase>
<goals>
<goal>eval-bsh-props</goal>
</goals>
<configuration>
<bshProps>
<property>
<name>mybuilddatetime</name>
<value>
mybuilddatetime = new Date().toGMTString();
</value>
</property>
<property>
<name>mysvnrevision</name>
<value>
mysvnrevision = -1; i = 0;
in_file = new FileInputStream(".svn/entries");
in_r = new InputStreamReader(in_file);
in = new BufferedReader(in_r);
StringBuffer sbr = new StringBuffer();
while(in.ready()){
line = in.readLine();
if(++i == 4) mysvnrevision = line ;
}
in.close();
</value>
</property>
</bshProps>
</configuration>
</execution>
</executions>
</plugin>
By introducing a build plugin that interprets configured Beanshell scripts and add the result as project properties I have created a very generic way for users to add arbitrary build properties through simple bsh scripts. In this way users may add logic that was not anticipated at forehand and in general it reduces the need for custom (3rd party) plugins.
This plugin is not (yet) part of GX WebManager but you could easily create your own. For now I am very curious to hear what people think of this approach. Should it become part of the SDK?
Regards,
Bram
Bram de Kruijff is Product Architect and one of the co-architects of the GX WebManager framework with a focus on OSGi and services framework. Bram is part of the NAF Web 2.0 forum group to define standards on community technologies.
Other blog entries: