How and why to create custom Ant tasks

Extend IBM Rational Application Developer functionality by invoking Eclipse APIs from Ant tasks

This article describes how to create custom Ant tasks within IBM Rational® Application Developer, which is built on the Eclipse platform. It also explains why you might want or need to do so. The example in this article provides a useful function not currently available in the integrated development environment (IDE): a custom Ant task that you can use to delete all generated files marked as derived.

Robert Weisz, Advisory Software Engineer, IBM Toronto Lab

Photo of Robert WeiszRobert Weisz works with the Rational Premium Support team at the IBM Toronto Lab, supporting Eclipse and Rational Application Developer.



24 March 2009

Also available in Japanese

Introduction

The Eclipse platform that IBM Rational® Application Developer is built upon provides many ways to extend its functionality; from writing your own plug-ins (which can access all of the Eclipse APIs and use its extension points, see Resources), to providing facilities to invoke external tools (for example, Javadoc, or Ant scripts, as its own builders, see Resources).

The example in this article uses a combination of both: you write a plug-in that contains a custom Ant task (which uses Eclipse APIs), and thereafter call this Ant task from an Ant script. You can invoke the script manually from the GUI, or add it to the builders list to be invoked during a Rational Application Developer and Eclipse build, as shown later in the article. Because the Ant task can be executed from either the Rational Application Developer GUI or the command line (headless), it can be a powerful mechanism to add functionality to batch, unattended, or nightly builds.

Background of the attached example

According to the Eclipse conventions, all automatically generated artifacts are marked with the derived flag (see Resources). The most common example of files marked derived, are the compiled Java™ class files (*.class), as shown in Figure 1.

Figure 1. Screen capture showing file properties, including the Derived flag
Shows the derived checkbox parameter

Another example of automatically generated files is Java source files (*.java), which can be generated from annotations or from WSDL (Web Services Description Language) files (for Web Services clients, for example). In addition, an example of automatically generated artifacts are the Enterprise JavaBeans™ (EJB) stubs generated by ejbDeploy during an application's deployment to IBM WebSphere® Application Server (or another server).

The point of this example is that most of those generated files do not get deleted during a Clean build (invoked using the menu action Project > Clean). The reason is that the Clean command usually scrubs the output folder, while the generated files are not usually put there.

There is a good reason for Clean not to delete generated source files: most of the time, you do not necessarily want to re-generate the automatically generated source code, mostly for performance.

But there are also good reasons to do complete (for example, nightly) builds. You might also want a complete build when modifications occur in some of the original source files (for example, the WSDL files), or in annotated files (on which the auto-generation is based). In those cases, it is advisable to delete the generated files as well, to ensure that no previously generated files are left behind. This is because they can cause all kinds of difficult-to-find problems, from compilation errors to runtime errors.

Just to put things in perspective: for nightly builds, you can easily achieve a complete build by ensuring that each build happens in a new workspace. In other words, first delete the old workspace, and then start a new workspace, populating it by checking out the various projects from the Source Control system (and so on). This approach assumes that no automatically generated files have been checked in to the Source Control system in the first place. Indeed, files marked derived are not supposed to be checked into Source Control systems (as mentioned at Derived resources).

On the other hand, for you as an individual developer, this approach of starting in a new workspace, although feasible, is not very practical due to the amount of time involved. This example will help you to delete all the files marked derived using a Custom Ant Task. This task can be invoked during an Ant build, either from the GUI or the command line. This new Ant task complements the current Clean command by ensuring that all of the derived files are deleted, in addition to whatever clean-up was done by Clean.

A word of caution before looking at this implementation: although the Eclipse definition of the usage of the derived flag is pretty clear, no one can anticipate how all of the different product groups who built their products on top of Eclipse actually implemented or interpreted its usage. In other words, there could conceivably be cases where files that shouldn't be marked derived are so marked (and therefore get deleted by this Ant task). There could also be files that should be marked derived and aren't, and hence they won't be deleted. In addition, one can refer to an existing discussion on the subject of whether Clean should also delete derived resources in the Eclipse bugzilla 126354 article as found in the References section.


Deleting the derived resources: the code

The following code was developed as an Eclipse Java project, prior to incorporating it into a Java archive (JAR) and packaging it into an Ant task plug-in. Listing 1 shows the relevant part of the code, which uses Eclipse APIs to search the workspace, recursively, for resources marked derived, and then deletes them. These are the two most significant methods doing the work in the Ant task.

Note:
The sample code was tested on Rational Application Developer V7 (which is based on Eclipse V3.2).

The complete code, including the source files, is packaged as a .zip file (see DeleteDerivedAttachments.zip in the Downloads area), ready to be deployed as an Eclipse plug-in into an existing Rational Application Developer and Eclipse installation. To do so, drag the "DeleteDerivedAntTaskPlugin_1.0.0.jar into your Rational Application Developer installation directory /SDP70/plugins folder. The .zip file also contains a build.xml file that will be described later.

The code shown in Listing 1 takes into consideration two possibilities:

  • Delete derived resources only in the current project (that is, the project where the Ant script build.xml file is placed)
  • Delete derived resources in the whole workspace

As you will see later, you can make the choice inside the build.xml file (the default is the current project scope).

Listing 1. Searching for and deleting derived resources
/**
 * Performs the "derived resources" deletion.
 *
 * @exception BuildException thrown if a problem occurs during execution.
 */
public void execute() throws BuildException
{
  log = ResourcesPlugin.getPlugin().getLog();
  IProject[] project = null;
  IProject currentProject = null;

  IWorkspace workspace = ResourcesPlugin.getWorkspace();
  IWorkspaceRoot  root = workspace.getRoot();
	
  if (cleanWorkspace)  // delete derived resources in the whole workspace
  {
    System.out.println("DeleteDerivedResourcesAntTask.execute()-
                                                clean all the workspace");
    project = root.getProjects();
    int length = project.length;
    for (int i = 0; i < length; i++)
    {
      if (project[i].isOpen())
      {
        System.out.println("delete all derived resources in project: " +
                                                          project[i].getName());
        try
        {
          IResource[] resourcesInProject = project[i].members();
          int projectMembers = resourcesInProject.length;
          for (int j = 0; j < projectMembers; j++)
          {
            try
            {							
              if (resourcesInProject[j].exists())
              {
                deleteAllDerivedResources(resourcesInProject[j]);
              }
            }
            catch (CoreException e)
            {
              e.printStackTrace(System.out);
            }						
          }					
        }
        catch (CoreException e)
        {
          e.printStackTrace(System.out);
          System.out.println("CoreException reading project members");
        }						
      }				
    }
  }
  else // delete derived resources only in the current project
  {
    antProject = getProject();
    baseDir = antProject.getBaseDir().getName();
    currentProject = root.getProject(baseDir);
    if (currentProject.isOpen())
    {
      try
      {
        IResource[] resourcesInCurrentProject = currentProject.members();
        int currentProjectMembers = resourcesInCurrentProject.length;
        for (int j = 0; j < currentProjectMembers; j++)
        {
          try
          {							
            if (resourcesInCurrentProject[j].exists())
            {
              deleteAllDerivedResources(resourcesInCurrentProject[j]);
            }
          }
          catch (CoreException e)
          {
            e.printStackTrace(System.out);
          }						
        }					
      }
      catch (CoreException e)
      {
        e.printStackTrace(System.out);
      }
    }
  }
}

/**
 * Delete a resource (file or folder) if it is derived.
 * (By definition, anything inside a derived folder is derived too.)
 *  If it is a non-derived folder, keep on recursing down the tree looking
 *  for derived resources.
 */	
public static void deleteAllDerivedResources(final IResource resource)
throws CoreException
{
  if (resource.isDerived())  // only Files and Folders can be derived.
  {                          //  Projects cannot be marked derived.
    deleteResource(resource);
  }
  else
  {
    if( resource.getType() == IResource.FOLDER )
    {
      IResource[] members = ((IFolder)resource).members();
      for( int i=0, length=members.length; i<length; i++ )
      {
        deleteAllDerivedResources(members[i]);
      }
    }		
  }
}

Creating the plug-in containing the Ant task

To begin, you will need to create a very simple plug-in to contain the Ant task implementation, packaged in a JAR file. Each plug-in needs to have a plugin.xml, which defines the plug-in to the Eclipse framework and points to the JAR library file. In this case, the plugin.xml file, shown in Listing 2, will also be used to declare the Ant task.

You should rely on the Eclipse Ant task specifications (see Resources) to declare a new custom Ant task.

The plugin.xml file

Listing 2. The content of the plugin.xml file
<?xml version="1.0" encoding="UTF-8"?>
        <?eclipse version="3.2"?> 
        <plugin> 
            <extension id="deleteDerived" name="deleteDerivedResources"
                point="org.eclipse.ant.core.antTasks"> 
            <antTask name="deleteDerived"
                class="com.rw.sample.DeleteDerivedResourcesAntTask" 
                library="antLib/AntLib.jar" headless="true" eclipseRuntime="true"/> 
            </extension>
        </plugin>

If you have no unexpected problems, your new Ant task should be recognized by Eclipse. It should also be displayed in the Window > Preferences > Ant > Runtime > Tasks menu, as shown in Figure 2.

Note: Of particular interest is the requirement to locate the Ant task library separately from the plug-in's JAR file. The AntLib.jar file is placed in a sub-folder of the plug-in, in order to avoid class loading issues. You want the Ant classloader to load the Ant task, rather than the plug-in's classloader, as per Eclipse bugzilla 34466 from the Resources section.

Figure 2. Eclipse showing the newly created deleteDerived Ant task
List showing the newly created delete derived item

The build.xml file

To run an Ant build, you need an Ant script in order for the Ant runtime to execute. This file is typically called build.xml. Ant scripts are .xml files. As an example, Listing 3 shows the build.xml that you will use to invoke your newly created custom Ant task. This build.xml file should be placed in the root of the project whose derived resources you want to clean (the project folder where the .project file is found).

To make the example Ant task more flexible, add the cleanCurrentProjectOnly option. If this option is true, it will delete only the derived resources located in the same project where the build.xml script file was placed. Otherwise, if it is set to false it will delete the derived resources in the whole workspace.

Listing 3. The content of build.xml file
<?xml version="1.0" encoding="UTF-8" ?>
    <project name="customAntTaskBuild" default="deleteDerivedTarget" basedir=".">
        <taskdef name="deleteDerived"
        classname="com.rw.sample.DeleteDerivedResourcesAntTask"> 
        </taskdef>
        <target name="deleteDerivedTarget" cleanCurrentProjectOnly="true" />
        </target> 
        </project>

Running the Ant build manually

Once the build.xml file is created, it is time to run it, in order to see how it works. To run it manually, right-click the build.xml file and select Run As > Ant Build, as shown in Figure 3.

Figure 3. Invoking an Ant build manually
Use the option menu to run the ant build

In most cases, you can run the build file accepting all of the defaults of the Launch Configuration wizard. The exception is the JRE tab. In order for your custom Ant task code to have access to the Eclipse APIs, you must run in the same JRE as Rational Application Developer and Eclipse. Figure 8 shows the settings necessary to accomplish this.


Running the Ant build automatically, as an Eclipse builder

By running the Ant build manually, you have full control over when you want to delete the derived resources.

On the other hand, there are some circumstances when it is preferable to have this automated (for instance, to link it to the Clean operation, specifically to ensure that the derived resources are deleted when you invoke Clean). You can achieve this by telling Eclipse to add the build.xml to its list of builders, as shown in Figure 4.

  1. Select the project where you stored the build.xml file.
  2. Select Properties > Builders.
  3. Click the New button.
Figure 4. Invoking the New Builder wizard
Use the build wizard dialog to select new project
  1. Select the Ant Build configuration type, as shown in Figure 5.
Figure 5. Selecting the Ant Build configuration
Select configuration dialog, choose Ant Build

The next steps set the various properties of the Ant Build configuration.

  1. On the Main tab, you set the Builder's name and point to the build.xml file that you created, as shown in Figure 6.
Figure 6. Setting the Main Ant Build configuration
Properties dialog screenshot
  1. After you have completed the settings on the Main tab, fill in the settings in the Targets tab, as shown in Figure 7.

Notice the various possibilities offered by the Eclipse platform in terms of when this builder should be invoked:

  • After a Clean
  • On every Manual build
  • On every Auto build
  • During a Clean

As shown in Figure 7, this example uses the option to delete the derived resources only During a Clean (the default target in the build.xml is the deleteDerived Ant task). This is because that is the only case where you want to delete them, for performance reasons.

  1. To do this, click the Set Targets button and make the appropriate selections.

This function does what Clean usually does and in addition ensures that all generated code is deleted as well.

Figure 7. Builder targets
Properties dialog showing default target for clean process

After you have completed the settings on the Targets tab, proceed to the JRE tab.

  1. Ensure that the Run in the same JRE as the workspace option is selected, as shown in Figure 8. (Recall that this is required in order for your Ant task code to have access to the Eclipse APIs.)
Figure 8. Selecting the Ant builder's JRE configuration
Properties dialog showing JRE runtime options
  1. At this point, you have completed the Builder's configuration. Therefore, click Save. You should see your newly defined builder in the list, as shown in Figure 9.
Figure 9. The updated list of Builders
Properties dialog showing builder list

There is one more consideration: in this case, it is essential that the generated (derived) resources get deleted prior to running any other builders, compilers, and so on.

  1. To change the order in which the builders are invoked, select your builder (Delete Derived resources Ant Builder) and repeatedly click the Up button, until your builder reaches the top line, as shown in Figure 10. Eclipse invokes the builders in order, starting from the top, with the last one being at the bottom.
Figure 10. Modified project builders invocation order
Properties dialog showing delete resource builder

Along the same lines, if the scope is to delete the derived resources in the whole workspace, then you need to ensure that the project containing your build.xml file will be built first among all of the other projects. This is so that it deletes all of the workspace's derived resources prior to any other project being built.

  1. To build your project first, assign it the appropriate order by selecting Window > Preferences > Workspace > Build Order, as shown in Figure 11.
Figure 11. Setting the build order of the projects in the workspace
Preferences dialog showing workspace build order

What you have learned

This article presented a powerful and flexible technique for extending your product's functionality. You can use this technique to achieve new goals specific to your team's requirements.

To highlight this point, see the Resources section for references to other applications that address specific needs using this custom Ant task technique, for instance Ant Tasks to import and export .epf files and Automating Modeling Compare Merge.


Acknowledgment

The author thanks Bob Dytyniak of the IBM Toronto Lab for reviewing this article.


Download

DescriptionNameSize
Sample Ant task for this articleDeleteDerivedAttachments.zip6KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Rational software on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Rational, Java technology
ArticleID=374171
ArticleTitle=How and why to create custom Ant tasks
publish-date=03242009