Ant Patterns – Continued

This is a follow up post of the previous one about the build tool Apache Ant and usage patterns called Ant Patterns.

Converting a Path to a Property

You can use Ant to gather a list of files from a fileset and convert this using pathconvert to a property with each file on a separate line. The property ${line.separator} is a JVM and OS dependent system property which is automatically available for every ant script.

<fileset id="my.files" dir="." includes="**/*.php">
      <!-- any condition, etc. ... -->
</fileset>
<!-- joins all files together into one string -->
<pathconvert pathsep="${line.separator}" property="my.files.flattend" refid="my.files"/>

The resulting property can then by piped to a program which receives the list on its standard input (STDIN) adhereing to the Unix principles. An example is shown below which uses a ruby script.

<fileset id="my.files" dir="." includes="**/*.php">
      <!-- any condition, etc. ... -->
</fileset>
<!-- joins all files together into one string -->
<pathconvert pathsep="${line.separator}" property="my.files.flattend" refid="my.files"/>
<!-- pipes the list of all files seperated by new lines to a script -->
<exec executable="ruby.exe" inputstring="${my.files.flattend}">
      <arg value="${my.script.name}"/>
</exec>

Note: Usage of the Ant Pattern Executing Platform Independent from the previous post in conjunction with this pattern is strongly recommended.

Ant as a Template System

Ant can use its property resolution mechanism for evaluating templates. This is useful if you need to generate files using templates. The templates can be read from any file while the properties can be stated within the ant file directly, read from a property file, xml file or requested from the user. An example is given below with leverages the copy task with its filterchain which can provide additional operations for the files to be copied, in this case the expansion of the properties. The filterchain basically implements the Unix pipes the Ant way.

<!-- make sure properties are set using the property, propertyfile, xmlproperty or input task -->
<property name="name" value="World" />

<!-- apply template by copying -->
<copy file="${template}" tofile="${target}"> 
  <filterchain> 
    <!-- fill the blanks with values -->
    <expandproperties/> 
  </filterchain> 
</copy>

Given the contents of the template.tt are Hello ${name}, the contents of the ${target} file will be Hello World.

This approach gives only simple property expansion as loops, conditions or any other mechanism normally used in templates does not work. However, this may suffice for some use cases.

Formatting XML Files Resulting from XSLT Transformations

Ant can use xslt stylesheets in the xslt task to transform a XML file to another XML file or simple text. In many cases, the result is another XML file which should look formatted well. However, Ant uses by default Apache Xalan as its XSL engine which contains a bug ignoring the indent attribute of the ouput tag. The listing below shows such the stub of a stylesheet which results in unindented XML code.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
    <!-- templates and stuff -->
</xsl:stylesheet>

This can be solved by adding the special indent-amount attribute to the output element with the namespace http://xml.apache.org/xslt and set it, for example, to 4 spaces.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt">
    <xsl:output method="xml" indent="yes" encoding="UTF-8" xalan:indent-amount="4"/>
    <!-- templates and stuff -->
</xsl:stylesheet>

More information about this can be found here.

Additional Links

Ant Patterns

Ant is a common build tool with very extensive documentation. It is still widely used and I recommend this tool for automating file system heavy steps. You can even call Ant tasks directly in Groovy using the AntBuilder which brings you an extremely powerful and well documented API without any hustle.

Here I have gathered a few Ant Patterns that you should be aware of when you build an Ant script.

Presence Validator for Properties

The properties can be loaded from a properties file, xml file or set directly using the property task. A property can only be defined once and cannot be overridden as it has the semantics of a final constant.

To ensure that a property is set, you can use the fail task to abort unless the property has been defined beforehand.

<fail unless="property.key"/>
<echo message="property.key = ${property.key}"/>

However, failing without a message makes the error very hard to come by. Therefore, the message attribute should be used to indicate the failure reason.

<fail message=""the property property.key is not defined" unless="property.key"/>
<echo message="property.key = ${property.key}"/>

If there are many property checks in a build file, these two lines have to be duplicated for every property to check. Much better is the use of a macrodef task which is basically a custom task with private properties named attributes.

<!-- definition of validate-presence-of-property task -->
<macrodef name="validate-presence-of-property">
       <attribute name="propertyKey"/>
       <sequential>
               <fail message="the property @{propertyKey} is not defined" unless="@{propertyKey}"/>
               <echo message="@{propertyKey} = ${@{propertyKey}}"/>
       </sequential>
</macrodef>

<!-- usage of the macrodef -->
<validate-presence-of-property propertyKey="my.property" />

The @{propertyKey} resolves to the given attribute value, in the example above to my.property. If you need the value of my.property, you have to evaluate it using the standard evaluation mechanism ${@{propertyKey}}.

The presented solution has been adapted from this presentation. This pattern can be reused for validate the presence of files, folders and the like using arbitrary conditions.

Default Values for Properties

A very common use case is to define a property with a default value and let the user override that value with a property file. As a property can only be initialized once, we can use this to implement this very simple by importing the properties from a file and try to set the properties to their default values afterwards. Setting the default value will fail (without an error) in case the property already exists.

<!-- include properties from file -->
<property file="my.properties"/>

<!-- set defaults which are only set if the properties do not already exist -->
<property name="some.property" value="default-value"/>

Updating/Removing Itself

Ant can delete/modify its own build file. This can be useful if you want to update the build file with an update target. A use case for this is to generate the build.xml from another xml file via xslt as I have implemented it in this project. In that case, I generate the build.xml from the manifest.xml of a Joomla extension.

<!-- updating using a stylesheet -->
<xslt in="manifest.xml" out="build.xml" style="some-stylesheet.xsl" force="true"/>
<!-- removing -->
<delete file="build.xml"/>

For this pattern, I was inspired by this blog post which shows that ant can delete itself.

Executing Platform Independent

Executing commands on the command line with ant can be problematic with the exec task. Under linux or Mac OSX you can execute the command directly while you need to prepend cmd /c under Windows as described here. Because the scripts should be platform independent, you can make use of the osfamily attribute of the exec task which executes the task only if the operating system matches the given osfamily.

<exec executable="cmd" osfamily="windows">
     <arg value="/c"/>
     <arg value="ruby"/>
     <arg value="-v"/>
</exec>
<exec executable="ruby" osfamily="unix">
     <arg value="-v"/>
</exec>

However, I you need to call several commands on the command line, you get code duplication. Macrodef to the rescue.

<!-- macro for executing a command plattform independent -->
<macrodef name="execute">
       <attribute name="executable"/>
       <element name="args" implicit="yes"/>
       <sequential>
                <exec osfamily="windows" executable="cmd">
                       <arg value="/c"/>
                       <arg value="@{executable}"/>
                       <args/>
                </exec>
                <exec osfamily="unix" executable="@{executable}">
                       <args/>
               </exec>
      </sequential>
</macrodef>

<!-- usage -->
<execute executable="ruby">
    <arg value="-v"/>
</execute>

Simple Usage Information

Most tools provide usage information when called without parameter. As we want to write self-documenting code, you can use the ant -p or ant -projecthelp commands which print all targets which have the description attribute set on the console. We can let Ant call itself via command line as shown in the following listing:

<project name="test" default="usage">
     <target name="usage" description="usage information">
        <exec executable="cmd">
            <arg value="/c"/>
            <arg value="ant"/>
            <arg value="-p"/>
        </exec>
    </target>
</project>

It is important to set the default attribute of the project to usage to call the usage target when no targets are specified.

You can combine the pattern Executing Platform Independet with this to get the following ant script:

<project name="test" default="usage">
     <target name="usage" description="usage information">
        <execute executable="ant">
            <arg value="-p"/>
        </execute>
    </target>
</project>

More about printing usage information in Ant can be found here.

Collection of Links for Other Useful Ant Tipps

Build BPEL project in netbeans using command line

As stated in a previous post, you can use the command line (in this case ANT) to build a BPEL netbeans project.

After asking the openESB community, which is very helpful and fast in their answering, it is not possible to get warnings. Only validation errors are presented for this.

Validation itself is configurable with these commands:

Nothing is validated: -Dvalidation=none
Only parts are validated: -Dvalidation=partial
Everything is validated: -Dvalidation=complete

For huge projects it can be better to use the none or partial validation option as the building takes too long otherwise.

References: openESB mailling list regarding this topic