Sign in

E-mail *, (xx@domain.com)
Password *

Register | Forgot password

Blogs

Recent blogs

RSS - Blogs
March 9, 2010
State of OSGi in the Java world
March 4, 2010
Reach more people with Google Translate
March 3, 2010
Get My Advice
February 26, 2010
What? Where!?!
February 11, 2010
Split it!

All Blogs...


Maven secrets: Dynamic Maven properties with Beanshell

May 29, 2008

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>
Conclusion

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





About the Author

Return to all blogs


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.

Read all Brams blog entries

Other blog entries:

June 26, 2009
Presentation at NAF Insight WEB 2.0
April 21, 2009
GX WebManager 9.8 on Java SE 6: The right stuff!
April 17, 2009
dOSGi talk at JSpring 2009
March 5, 2009
Accessing services in GX WebManager
June 3, 2008
A few SDK tips & tricks
May 27, 2008
GX WebManager on SpringSource Application Platform
May 9, 2008
JavaOne 2008 wrapup
April 14, 2008
Maven secrets: assembling a WCB zip
April 11, 2008
ApacheCon EU 2008 impressions
April 4, 2008
OSGi techtalk at JTeam


Share:

del.icio.us
digg
Technorati
Slashdot
Reddit
YahooMyWeb
NewsVine
ekudos
© 2010 GX creative online development B.V.

Disclaimer

This website (GXdeveloperweb.com) may discuss or contain opinions, (sample) coding, software or other information that does not include GX official interfaces, instructions or guidelines and therefore is not supported by GX. Changes made based on this information are not supported.  GX will not be held liable for any damages caused by using or misusing the information, software, instructions, code or methods suggested on this website, and anyone using these methods does so at his/her own risk. GX offers no guarantees and assumes no responsibility or liability of any type with respect to the content of this website, including any liability resulting from incompatibility between the content of this website and the materials and services offered by GX. By using this website you will not hold, or seek to hold, GX responsible or liable with respect to the content of this website.