Core concepts

Overview

Ant4Eclipse provides a set of Ant-tasks that you can use to access and process your Eclipse project settings from your Ant buildfiles. Using ant4eclipse you can write build scripts that are driven by the configuration you made for your projects in Eclipse without to duplicate your configuration (like a projects classpath, its output- and source folders) in Eclipse and in Ant.
The Ant4Eclipse task can be grouped into three categories:

  • Executors: Executors are special tasks that directly "work" on a special workspace or project artifact (an artifact might be a single project or a launch configuration etc). An Executor passes all information about such an artifact (like it's name, it's location, it's classpath etc - depending on the concrete artifact) to "sub-tasks" in your build file. You can implement those sub-tasks (that work like callback methods in a programming language) in your build file to process the artifact (for example to compile the current project). You can learn more about Executors here
  • Tasks: Ant4Eclipse-Tasks are technically regular Ant tasks, that allow you to read configurations from your Eclipse projects and make them available to your build file via Ant properties, pathes, references etc. In opposite to Executors when using tasks you explizitly "ask" for a specific information while an Executors provide all important information automatically for you.
  • Conditions: Ant4Eclipse shipps with several Ant-Conditions that can be used to determine if a project has a specific setting (for example if it has a specific nature). You can use them for example with the if-task, that is part of the antcontrib project.

Macros

In additions to the tasks mentioned above ant4eclipse comes with a set of macros that provide out-of-the-box-solutions for some common tasks (like compiling a whole java project or building a plug-in). The macros can be found in several xml-files inside the "macros" subfolder in the ant4eclipse distribution. (Note: of course the macros are using the ant4eclipse tasks so they are a good demonstration of their usage).

Where is the Eclipse configuration?

Ant4Eclipse directly works with your project configuration thus eliminating the need of re-configuration your setup in your build file. Your Eclipse project setting completely drives your build. But there are some configurations that are not part of your project, but part of the workspace or Eclipse preferences. The JREs you define in Eclipse for example are stored in the .metadata directory in your workspace. If you make a clean checkout of your project (for example in a nightly build), these informations are not available (to ant4eclipse) and need to be re-configured in ant4eclipse. Anyway that is pretty straight forward and we’ll show you in the following sections how you do this.

The Eclipse Workspace

Executors

An Executor is a special kind of an Ant task. Executors "executing" a project artifact (like a Team Project Set, a Project, or a Launch configuration). Executing means that the executors parses the artifact and calls several callbacks targets, passing in the information just parsed (like the name of a project, it's classpath, it's source- and output folder, the main class to launch etc). The potential call back targets are executor-specific and are implemented in your build file as a sub element to the executor task.

The usage of Executors has several advantages including:

  • Iteration and filtering: you can easily iterate over a list of children of a project artifacts for example over a list with all projects inside a Team project set. If you only want to access some of list's elements you can use a filter to filter the elements of your interest. You could for example iterate over all projects filtering those projects that have a specific nature.
  • Accessing informations: The executors passing all relevant information of the project artifact to the callback targets. You can immediately work with them. There is no need to call targets that determine specific informations.
  • Scoping: The properties, pathes and references that are passed from an Executor to your build file are automatically scoped, that is they are only valid while the Executor resp. one of its call back targets is executed. Ant4eclipse makes sure that you always see what's relevant for your target. You don't need to manage the properties etc. yourself.

Let's have a look at an example. Imagine you want to iterate over all projects contained in a Team Project Set (psf) file, for example to build those projects In the first step you have to iterate over all projects of that file. For this task ant4eclipse provides the executeProjectSet-Executor. This executor calculates the correct dependency hierarchy of the projects (for example according to their classpathes) and invokes the forEachProject subtask for each project in the psf-file. In each iteration ant4eclipse passes some properties and references to the subtask describing the current project (for example it's name). The following snippet echoes the name of all project names in their correct build order:

<ant4eclipse:executeProjectSet workspace="c:/myworkspace" teamprojectset="my-project.psf" projectReferenceTypes="jdt">
 <ant4eclipse:forEachProject>
  <!-- Note that ${executeProjectSet.project.name} is passed in by ant4eclipse -->
  <echo>Project that should be build: ${executeProjectSet.project.name}</echo>
 </ant4eclipse:forEachProject>
</ant4eclipse:executeProjectSet>

It is even possible to use Executors within other Executors. We could enhance the previous example with the executeJdtProject-Executor, that works on an JDT-project and provides among others information about the classpath, source- and output-folders of a project. Let's dump the classpathes of all Projects:

<ant4eclipse:executeProjectSet workspace="c:/myworkspace" teamprojectset="my-project.psf" projectReferenceTypes="jdt">
 <ant4eclipse:forEachProject>
  <!-- Note that ${executeProjectSet.project.name} is passed in by ant4eclipse -->
  <echo>Project that should be build: ${executeProjectSet.project.name}</echo>
  <ant4eclipse:executeJdtProject workspace="c:/myworkspace" projectName="${executeProjectSet.project.name}"
   <ant4eclipse:forProject>
    <echo>Classpath of project: ${executeJdtProject.classpath.absolute.compiletime}</echo>
   </ant4eclipse:forProject>
  </ant4eclipse:executeJdtProject>
 </ant4eclipse:forEachProject>
</ant4eclipse:executeProjectSet>

Note that the allowed sub-tasks of an Executor can be used in any order and they are allowed to implement them as often as you need them. You could for example use the forEachOutputDirectory sub-task of the executeJdtProject-Executor at the beginning to clean the output directory before compiling. Then you use the forProject sub-task to compile your project. In the last step you could again use forEachOutputDirectory to instrument classes you just compiled:

 <ant4eclipse:executeJdtProject workspace="c:/myworkspace" projectName="${executeProjectSet.project.name}">
  <!-- 1. step: clean up all output directories -->
  <ant4eclipse:forEachOutputDirectory>
   ... 
  </ant4eclipse:forEachOutputDirectory>
 
  <!-- 2. step: build the whole project -->
  <ant4eclipse:forProject>
   ...   
  </ant4eclipse:forProject>
 
  <!-- 3. step: instrument the compiled classes -->
  <ant4eclipse:forEachOutputDirectory>
   ...   
  </ant4eclipse:forEachOutputDirectory>
 </ant4eclipse:executeJdtProject>

Note: more real-world examples of Executors can be found in our ant4eclipse build-file.

Filtering

We just have seen that some Executors iterate over a set of items, for example a list of projects or a list of output folders etc. Sometimes it's desired to filter such a list according to some criterias.

if and unless

The easiest way to filter is to use the if or unless attributes on the sub-tasks of an executor. You can pass in a variable that expands to true or false. If the variable evaluates to true the sub-tasks gets executed (if using the if attribute) or is skipped (if using the unless attribute) and vice versa. This is quite common to the if and unless attribute that some built-in ant tasks provides. In the following example the second forEachOutputDirectory only gets invoked if the variable instrumentProjectClasses is set to true:

 <ant4eclipse:executeJdtProject workspace="c:/myworkspace" projectName="${executeProjectSet.project.name}">
  <!-- 1. step: clean up all output directories -->
  <ant4eclipse:forEachOutputDirectory>
   ... 
  </ant4eclipse:forEachOutputDirectory>
 
  <!-- 2. step: build the whole project -->
  <ant4eclipse:forProject>
   ...   
  </ant4eclipse:forProject>
 
  <!-- 3. step: instrument the compiled classes (only when 'instrumentProjectClasses' is set to 'true' -->
  <ant4eclipse:forEachOutputDirectory if="${instrumentProjectClasses}">
   ...   
  </ant4eclipse:forEachOutputDirectory>
 </ant4eclipse:executeJdtProject>

filter

While this approach allows you some simple filtering in some circumstances it's not enough. In the example above instrumentProjectClasses is a regular static Ant variable. It's value doesn't change from one invocation of forEachOutputDirectory to another. But what if you want to instrument the classes in the output directory depending on the name of the current (for example if you want to instrument only those directories whose name don't end with .test)? For such cases ant4eclipse providers another, more powerful and flexible option: filters. All sub-tasks provide a filter element that can be used to specify an LDAP-like query expression. Within this query you can access all scoped properties that are provided by the sub-task and it's parent Executor and compare them with your desired values.
Let's consider the example mentioned above, where you want to only instrument directories whose names not ending with .test. In this case you could use the following filter:

 <ant4eclipse:executeJdtProject workspace="c:/myworkspace" projectName="${executeProjectSet.project.name}">
  <!-- 1. step: clean up all output directories -->
  <ant4eclipse:forEachOutputDirectory>
   ... 
  </ant4eclipse:forEachOutputDirectory>
 
  <!-- 2. step: build the whole project -->
  <ant4eclipse:forProject>
   ...   
  </ant4eclipse:forProject>
 
  <!-- 3. step: instrument the compiled classes (only when directory name doesn't end with '.test' -->
  <ant4eclipse:forEachOutputDirectory filter="(!(output.directory=*.text))">
   ...   
  </ant4eclipse:forEachOutputDirectory>
 </ant4eclipse:executeJdtProject>

Filter syntax
Filter expressions are based on the RCF 1960 "A String Representation of LDAP Search Filters". A filter is built of one ore more Criterias where each criteria defines a request to an attribute, that must be the name of a scoped property from the enclosing executor or it's sub-task, where you specify the filter. The specified value can contain an asterisk (*) to specify a wildcard that matches any set of characters. The following criterias are possible:

  • Equality: (attribute=value)
  • Greater-or-equal-than comparsion: (attribute>=value)
  • Less-or-equal-than comparsion: (attribute<=value)

Several criterias can be combined using Operators. An operator is written before the criteria. Both, the operator and the criteria are surrounded by parenthesis. Ant4Eclipse supports the following operators:

  • AND: (&amp; (criteria-1)(criteria-2)). It's even possible to specifiy more than two criterias: (&amp; (criteria-1)(criteria-2)(criteria-n))
  • OR: (| (criteria-1) (criteria-2). It's even possible to specifiy more than two criterias: (| (criteria1)(criteria2)(criteria-n)
  • NOT: (! (criteria-1)

Example
A filter that checks whether the scoped property project.name starts with "org." or "net." would look like this:

(|(project.name=org.*)(project.name=net.*))

Macros

Project types

Since Eclipse is a platform that is not only used for developing Java applications but that works as a basis for development environments for several languages (for example C/C++, Python, PHP) and use cases (for example Web Development, Plug-in Development, Database development) it has an extensible concept of projects. There is not the one project type that is identical for all purposes. The most simple project type is the General Project that is defined in Eclipse' platform layer and that is more or less a "container" for files. A General Project doesn't know anything about programing languages, compilers etc. It just have a name and a location and it can be managed by the version control system features Eclipse provides (CVS, Subversion etc).

To support more than the General Project type, projects can get several natures assigned. A nature is a unique identifier (typically provided by a Plug-in) that is stored in the project's .project file. Plug-ins (and Features) installed in Eclipse (for example the Java Tooling or the Plug-in dev. env) can access the natures of a project and can deceide if they need to participate in someway in that project. Some Plug-ins need more configuration options (like a classpath) that cannot be stored inside the .project. Such Plug-ins typically work in addition with proprietary config files that are stored in the project (often as hidden files or directories starting with a .). An example is the .classpath file that specifies the Java classpath of a JDT/Java project. Of course it's possible that projects have more than one nature assigned. A Plug-in project from the Plug-in development environment (PDE) for example contains among the javanature it's own org.eclipse.pde.PluginNature.

Ant4Eclipse' tasks are grouped in layers that are related to a specific feature (as they are in Eclipse).

  • Platform: Tasks from this layer work with all projects, even with General projects.
  • JDT: The JDT-based tasks add Java-specific features, like resolving the classpath of a project.
  • PDE: The PDE layer contains the support building Eclipse Plug-ins and features. They can only be used with PDE-projects. Since a PDE project is a JDT project as well, you can use all tasks from JDT layer with your PDE projects.
  • STS: Work with projects from the SpringSource ToolSuite. This tasks are work-in-progress and will be added in later releases to ant4eclipse
  • Python: Support for python projects