Skip to Content

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.*))