November 27, 2014
Hot Topics:

More on Custom Ant Tasks

  • October 5, 2006
  • By Rob Lybarger
  • Send Email »
  • More Articles »

This article is a continuation of the article " Introduction to Custom Ant Tasks." Reading through the previous article is highly recommended because I am just going to pick up where I left off last time. For this reason, my examples in this article will start numbering at five (5). I am assuming you have a moderate level of experience with Ant on your platform-of-choice. (I use Windows 2000 during the day and Mac OS X when I'm at home.) Also, my code examples use some of the newer Java syntax bits such as enhanced-for and generics.

I left off in the first article just shy of mentioning nested elements. My reason for deferring the topic was that I wanted enough material and explanations to be valuable. However, before we get into the actual mechanics of nested elements, let's take a moment to cover custom types.

Topics in this article

  • Types versus Tasks
  • Custom Condition Types
  • Handling Specific Nested Types
  • Handling Arbitrary Nested Types
  • Task with Nested Tasks
  • Nesting Tasks and Conditions
  • Custom Selectors
  • XML Namespaces

Types versus Tasks

Types are anything that lack an execute() method. This means that Ant will not attempt to call the execute() method when it encounters them. Instead, the parent element will interact with the type via some appropriate method calls which are entirely up to the developer to provide. This being the case, types serve as auxillary helpers for other tasks, usually as nested child elements. You may note that Ant does provide the org.apache.tools.ant.types.DataType class from which many of Ant's own types derive. However, it is perfectly fine for your own tasks to (implicitly) derive directly from java.lang.Object. (Also, although I have yet to personally verify this, I suspect a publicly accessible inner class might also work, provided the typedef is correctly set.)

Ant maintains a distinction between tasks and types to the point that you declare types with a typedef task instead of a taskdef task. For the sake of the example, this means you will list your custom types in a second properties file.

Aside from the setter methods to support attributes in the build file, other methods you provide are at your discretion. Indeed, the whole reason for the type to exist might be limited to the support of exactly one other task or type, or it might be a more generic and flexible type that you use across multiple tasks or types. Ant, for example, has the fairly specific arg element underneath the exec task and the fairly generic fileset element which is supported throughout many Ant tasks which need to deal with files. There are even a few special-purpose categories of types in Ant, the condition type (not to be confused with the <condition> task itself which contains nested condition types) being notable.

Custom Condition Types

Ant has a task called condition, but the various elements which nest underneath it are condition types. Some examples familiar to Ant script writers include isset (for properties) and available (for files and resources) as well as the logicals and and or and the negation not. It may happen that you need some logic to happen based on a condition which is either exceedingly cumbersome to write with the standard condition types, or which is just not possible. Writing a custom condition type is almost identical to writing a custom task:

  1. Implement org.apache.tools.ant.taskdef.condition.Condition interface
  2. Implement public boolean eval() method
  3. Provide standard instance variables and setter methods for attribute support, if needed

Remember when I said the parent element interacts with a type element via some appropriate method? For a condition type, this is the role of the eval() method which returns a boolean value.

Now, once your Java source code is written, create a properties file to map your Java class to an Ant element name. Do not list your custom type in the same properties file you are using for custom tasks; they need to be referenced by separate typedef and taskdef task statements, respectively.

Example 5: A Numerical "Greater Than" Condition

The standard conditions do not support checking numerical-based comparisons such as greater than, less than, or equal to. This is how a numerical greater than condition would work:

//NumGreaterThanCondition.java
package org.roblybarger;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.condition.Condition;

public class NumGreaterThan implements Condition {

   private double arg1;
   private double arg2;

   public double getArg1() {
      return arg1;
   }
   public void setArg1(double arg1) {
      this.arg1 = arg1;
   }
   public double getArg2() {
      return arg2;
   }
   public void setArg2(double arg2) {
      this.arg2 = arg2;
   }
   public boolean eval() throws BuildException {
      return (arg1>arg2);
   }
}

Create MyAntTypes.properties (if necessary) and add this entry:

numgt=org.roblybarger.NumGreaterThanCondition
Update your jar file, and then use an Ant script similar to this to put the custom condition to use:

<project name="ex5" default="demo" basedir=".">

   <typedef resource="MyAntTypes.properties"
            classpath="myant.jar"/>

   <target name="demo">

      <property name="valueA" value="10.34"/>
      <property name="valueB" value="9.52"/>

      <fail message="${valueA} is NOT greater than ${valueB}">
         <condition>
            <not>
               <numgt arg1="${valueA}" arg2="${valueB}"/>
           </not>
         </condition>
      </fail>

      <echo message="valueA is greater than valueB"/>

   </target>
</project>

Something like this might be useful if you wanted to verify that you have sufficient disk space before attempting to copy a large file. (The OS-specific details of computing available disk space are left as an exercise to the reader.) You also might employ custom conditions elsewhere to perform sanity checks or enforce business logic rules at various places in your build. Providing a collection of small, focused conditions is better than one monolithic condition: The smaller condition types can be reused more easily, and overall maintenance is reduced to minor updates your ant script should your business rules change slightly.





Page 1 of 4



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel