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
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.xmlfile 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.
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
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
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.
- Select the project where you stored the
build.xmlfile. - Select Properties > Builders.
- Click the New button.
Figure 4. Invoking the New Builder wizard
- Select the Ant Build configuration type, as shown in Figure 5.
Figure 5. Selecting the Ant Build configuration
The next steps set the various properties of the Ant Build configuration.
- On the Main tab, you set the Builder's name and point to the
build.xmlfile that you created, as shown in Figure 6.
Figure 6. Setting the Main Ant Build configuration
- 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.
- 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
After you have completed the settings on the Targets tab, proceed to the JRE tab.
- 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
- 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
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.
- 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
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.
- 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
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.
The author thanks Bob Dytyniak of the IBM Toronto Lab for reviewing this article.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample Ant task for this article | DeleteDerivedAttachments.zip | 6KB | HTTP |
Information about download methods
Learn
- Refer to Eclipse Platform Extensions (Eclipse 3.2 Online Help).
- Refer to Project Builders (Eclipse 3.4 Online Help).
- Refer to Project Builders (Eclipse 3.2 Online Help).
- Refer to Derived resources (Eclipse 3.2 Online Help) Explanation on what "Derived resources" are.
- Refer to Eclipse bugzilla 126354 Project Clean extension specific to derived files.
- Refer to Eclipse bugzilla 34466 Ant tasks classloading requirements.
- Refer to Eclipse Ant task specifications (Eclipse 3.2 Online Help).
- Refer to Ant Tasks to import and export .epf files to set the preferences of new workspaces (IBM technote).
- Refer to Automating Modeling Compare Merge: Running an Ant task on the IBM Rational Software Delivery Platform by Natalia Balaba-Liaskovski (developerWorks, July 2008).
- Visit the Rational software area on developerWorks for technical resources and best practices for Rational Software Delivery Platform products.
- Subscribe to the IBM developerWorks newsletter, a weekly update on the best of developerWorks tutorials, articles, downloads, community activities, webcasts, and events.
- Subscribe to the Rational Edge newsletter for articles on the concepts behind effective software development.
-
Explore Rational computer-based, Web-based, and instructor-led online courses. Hone your skills and learn more about Rational tools with these courses, which range from introductory to advanced. The courses on this catalog are available for purchase through computer-based training or Web-based training. Additionally, some "Getting Started" courses are available free of charge.
Get products and technologies
-
Download trial versions of IBM Rational software.
-
Download these IBM product evaluation versions and get your hands on application development tools and middleware products from DB2®, Lotus®, Tivoli®, and WebSphere®.
- Download IBM product evaluation versions and get your hands on application
development tools and middleware products from DB2®,
Lotus®, Rational®, Tivoli®, and
WebSphere®.
Discuss
- Participate in the discussion forum.
- Check out developerWorks
blogs and get involved in the developerWorks
community for forums, podcasts, wikis, and more.





