## Archive for the 'Tutorial' Category

### Writing a plugin

In a previous article you have been guided to write project specific logic to implement a new feature in easyant : code coverage.
We will see here how to extract this specific logic into a reusable easyant plugin.

## Generating plugin from a skeleton

First, we need to create a new plugin structure. To ease plugin development easyant came with a skeleton for plugins.
Skeletons plugin works by default in interractive mode, so it will ask a few questions.

> easyant skeleton:newplugin

-skeleton:check-generate:
...
[input] The path where the skeleton project will be unzipped [.]

[input] Organisation name of YOUR project [org.apache.easyant.plugins]

[input] Module name of YOUR project
cobertura
[input] Revision number of YOUR project [0.1]


We choose default value between brackets except for the module name.
For maven users :

• organisation = groupId
• module = artifactId
• revision = version

We’ve a ready to use plugin structure. Plugin structure is very similar to a standard easyant project scructure with :

• a module ivy file containing revision number, description and plugin dependencies
• src/main/resources containing the plugin logic (.ant files but also a good place to put additionnal files required by the plugin)
• src/test/antunit containing plugin tests
|-- module.ivy
-- src
|-- main
|   -- resources
|       -- cobertura.ant
|-- test
-- antunit
-- cobertura-test.xml


## Ant file

The skeleton has generated the plugin main file in src/main/resources/cobertura.ant

<project name="org.apache.easyant.plugins;cobertura"
xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:ea="antlib:org.apache.easyant">

<!-- Force compliance with easyant-core to 0.7 or higher -->
<!-- <ea:core-version requiredrevision="[0.7,+]" /> -->

<!-- Sample init target -->
<target name="cobertura:init">
<!-- you should remove this echo message -->
<echo level="debug">This is the init target of cobertura</echo>
</target>
</project>


By convention, projectname of the plugin should be formed like

[organisation];[module]


Example:

org.apache.easyant.plugins;cobertura


### Understanding extension-point

Extension-points are plugins hooks.  Plugins typically add low-level tasks to one or more extension-points. For example, a plugin can contribute to processing sources before compilation, you will in that case plug your own target to “abstract-compile:compile-ready” extension-point”. This plugin hooks is defined in abstract-compile plugin”.

So we need to import this plugin and plug our own target on it.

<ea:plugin module="abstract-compile" revision="0.9"/>
</target>


Less typically, a plugin can also define new extension-points for other plugins to use. We highly recommend in that case to create an “abstract” plugin defining common stuff and extension-points to limit coupling between plugins and make them more flexible.

In standard build types the project-lifecycle is defined by a plugin named phases-std. This plugin loads the default lifecycle containing a set of high level extensionPoints like compile,package.
It’s build types responsability to import this plugin and and do the binding between targets and extension-points from this lifecycle.

### Target Naming Conventions

By default, all targets should be prefixed by plugin name. In our example “init” target is prefixed by “cobertura”.

There is a conventional difference in the way public and private targets are named in Easyant. A public target is one that makes sense for the end user to be aware of, while a private target should be hidden from the end user.

Conventionally,

• a public target should always have an associated ‘description’ attribute.
• a private target should begin with a “-“

Those conventions are not mandatory. They just ease understanding.

Example :

<target name="cobertura:helloworld" depends="cobertura:init" description="display an hello world">
<echo>hello world !</echo>
</target>

<target name="cobertura:hello" depends="cobertura:init,-check-username" description="display an hello to current user">
<echo mess="Hello ${username}"/> </target>  Whereas a private target name should begin with ‘-‘. Example : <!-- this target initialize username property if it's not already set --> <target name="-cobertura:check-username" unless="username"> <echo>You can also add a "-Dusername=YOU" on the commandline to display a more personal hello message</echo> <property name="username" value="${user.name}"/>
</target>


## Implementing the logic

It is now time to extract cobertura targets from project specific logic in a plugin.

<target name="cobertura:init">
<ivy:cachepath pathid="cobertura.classpath" inline="true" organisation="net.sourceforge.cobertura" module="cobertura" revision="1.9.4.1" conf="default" settingsRef="easyant.ivy.instance"/>
</target>

<target name="cobertura:instrument" depends="cobertura:init,compile,abstract-test:init">
<property name="coverage.dir" value="${target}/coverage"/> <property name="coverage.datafile" value="${coverage.dir}/cobertura.ser"/>
<mkdir dir="${coverage.dir}"/> <!-- delete previous coverage data file --> <delete file="${coverage.datafile}" />

<!-- do instrumentation -->
<cobertura-instrument todir="${coverage.dir}" datafile="${coverage.datafile}">
<fileset dir="${target.test.classes}" erroronmissingdir="false"/> <fileset dir="${target.test.integration.classes}" erroronmissingdir="false"/>
</cobertura-instrument>
<!-- contribute to test runtime classpath and prepend instrumented classes -->
<ea:path pathid="run.test.classpath" overwrite="prepend">
<fileset dir="${coverage.dir}"/> </ea:path> </target> <target name="cobertura:run" depends="cobertura:instrument"> <cobertura-report format="html" destdir="${target.report.dir}" srcdir="${src.main.java}" datafile="${coverage.datafile}"/>
</target>


### Import existing plugins

Cobertura plugin needs a few properties and classpaths defined in abstract plugins. Reusing exist stuff (properties, classpath, targets, etc…) avoids reinventing the wheel on each plugin and limit coupling two concrete plugins.
This can be achieved by import plugins like this :

<ea:plugin module="abstract-test" revision="0.9"/>
<ea:plugin module="abstract-compile" revision="0.9"/>


#### Reusing existing properties

Invoking ProjectMan command allow you to see properties available :

> easyant -listProps


To have only properties of a given plugin you could invoke

> easyant -listProps abstract-compile


To get more details on a given property you could invoke describe man command

> easyant -describe target.test.classes


This commands tell us it’s a property withs it’s description, default value and lot of interesting informations.

	No extension point found for name: target.test.classes
No Target found for name: target.test.classes
Property: target.test.classes
Description: destination directory for compiled test classes
Default: ${target}/test/classes Required: false Current value:${target}/test/classes
Defined in:
No Parameter found for name: target.test.classes


#### Reusing existing extension points

To limit coupling with default lifecycle we should not directly rely on compile phase. Instead we highly encourages you to plug your stuff into existing extension points from other plugins.
Invoking ProjectMan command allow you to see extension points available :

> easyant -listExtensionPoints


To have only extension points of a given plugin you could invoke

> easyant -listExtensionPoints abstract-compile


Let’s update target dependencies from :

<target name="cobertura:instrument"
depends="cobertura:init,compile,abstract-test:init">


to

<target name="cobertura:instrument"
depends="cobertura:init,abstract-compile:compile,abstract-test:init">


## Pre conditions

A build module should always check that a set of pre conditions is met.
This can be done at the root level of your plugin or in a target. We encourage you to use a target for initialisation as you can control when it should be executed. If intialisation is done at the root level it will be executed when the plugin is loaded.

By convention, the initialisation target should be named “<plugin>:init”.

Pre conditions, including for example – checking the existence of a file or a directory, could be performed inside this target. Additionally, this target is a great place to do global initializations that are needed for the rest of the build. This could include a taskdef initialization.
Pre conditions can be performed by using the parameter task.
Let’s refactor our plugin and document properties

<ea:parameter property="cobertura.instrumented.classes.dir"
description="Specify the output directory for the instrumented classes"
default="${target}/coverage"/> <ea:parameter property="cobertura.datafile" description="Specify the name of the file to use for storing the metadata about your classes. This is a single file containing serialized Java classes. It contains information about the names of classes in your project, their method names, line numbers, etc. It will be updated as your tests are run, and will be referenced by the Cobertura reporting command." default="${cobertura.instrumented.classes.dir}/cobertura.ser"/>
<ea:parameter property="cobertura.include.classes.regex"
description="Include regex pattern to select files you want to be instrumented"
default=".*"/>
<ea:parameter property="cobertura.exclude.classes.regex"
description="Exclude regex pattern to ignore files to be instrumented"
default=".*\.Test.*"/>
<ea:parameter property="target.reports"
description="base directory for reports"
default="${target}/reports" /> <ea:parameter property="target.coverage.reports" default="${target.reports}/coverage"
description="base directory where coverage reports will be generated" />
<ea:parameter property="cobertura.src.dir"
default="${src.main.java}" description="directory containing main sources (used for reports)" />  Elements defined through ea:parameter : • are documented • preconfigured with default values • can be required if they have no default values (useful if you need user input). If not present required property will fail the build and show parameter description. • will be used by ProjectManCommands (kind of interractive help on command line) • will soon be used by others tools (like IDE :)) ### What should be documented As the plugin may be used in many different ways we need to document following elements : • public targets / extension points descriptions • parameters (properties, resource collections, paths). For each parameter specify name, description, whether it is required, and optionally a default value. This should be done with the parameter task • expected environment (files in a directory, a server up and running, …) • results produced ## Adding plugin dependencies Most of the time when we write plugins we want to use third party ant tasks. Here we need to depend on cobertura.jar. Since we are now writing a plugin with it’s own module.ivy file we could remove the ivy:cachepath task in cobertura:init and add it as a dependency : <dependencies> <dependency org="net.sourceforge.cobertura" name="cobertura" rev="1.9.4.1" /> </dependencies>  ### Using dependency in your plugin ant script Easyant automatically creates a classpath specific for each plugin, this classpath contains all the required dependency .jars The classpath is named by conventions [organisation]#[module].classpath  Example: org.apache.easyant.plugins#cobertura.classpath  Since this classpath is auto-created you can use it to reference your taskdef.  <taskdef resource="tasks.properties" classpathref="org.apache.easyant.plugins#cobertura.classpath" />  ## Compatibilty with core revision A module can be dependent on features available in Easyant core. As such, it is possible for a module to be functional with particular versions of Easyant only. Easyant provides a way for modules to explicitly specify their dependency on core revisions. A module may use the ea:core-version task to specify such a dependency. A task may depend on: • static version (Example : 0.5) • dynamic version (Example : latest.revision) even if we do not recommand to use it • listed version (Example : (0.1,0.3,0.5) ) • range version (Example : [0.5,0.8] means from 0.5 to 0.8. Example2 : [0.5,+] means all version superior to 0.5) <!-- Force compliance with easyant-core to 0.9 or higher --> <ea:core-version requiredrevision="[0.9,+]" />  ## Publishing your plugin You can easily publish your plugin to an easyant repository using the standard phases publish-shared (for snapshot) or release > easyant publish-local > easyant publish-shared > easyant release By default plugins are published to a repository named easyant-shared-modules stored in$USER_HOME/.easyant/repository/easyant-shared-modules/.

You can specify the repository name using one of the following property

• release.resolver
• snapshot.resolver
Note: Repository must exist in easyant ivy instance. See configure easyant ivy instance man page for more informations.

Considering that you published your plugin in a easyant repository, you could use it in your project.

<ivy-module version="2.0" xmlns:ea="http://www.easyant.org">
<info organisation="org.mycompany" module="myproject"
status="integration" revision="0.1">
<ea:build module="build-std-java" revision="0.9">
<ea:plugin organisation="org.apache.easyant.plugins" module="cobertura" revision="0.9"/>
</ea:build>
</info>
<publications>
<artifact name="cobertura" type="ant"/>
</publications>
</ivy-module>


And now running

> easyant -p 

We should see cobertura’s target.

Main targets:
...
cobertura:run                   generate cobertura reports
...


### Writing plugin test case

By default the skeleton has generated a antunit test file in src/test/antunit/[module]-test.ant.

So in our case let’s open “src/test/antunit/cobertura-test.xml”

<project name="org.apache.easyant.plugins;cobertura-test"
xmlns:au="antlib:org.apache.ant.antunit"
xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:ea="antlib:org.apache.easyant">

<property name="target" value="target/test-antunit"/>
<!-- configure easyant in current project -->
<ea:configure-easyant-ivy-instance / >
<!-- import our local plugin -- >
<ea:import-test-module moduleIvy="../../../module.ivy" sourceDirectory="../../main/resources"/ >

<!-- Defines a setUp / tearDown (before each test) that cleans the environment -- >
<target name="clean" description="remove stale build artifacts before / after each test" >
<delete dir="${basedir}" includeemptydirs="true" > <include name="**/target/**"/ > <include name="**/lib/**"/ > </delete > </target > <target name="setUp" depends="clean"/ > <target name="tearDown" depends="clean"/ > <!-- init test case -- > <target name="test-cobertura:init" depends="cobertura:init"> <au:assertLogContains level="debug" text="This is the init target of cobertura"/> </target> </project>  Here we : • configure easyant for test • import the plugin • define a generic tearDown, setUp method that cleans the target and lib directories. • define a test case for the init target that check that the output log contains “This is the init target of cobertura” All targets prefixed by “test” will be executed as a test case (similar to junit 3 behavior). Now we will write a test case for our “cobertura:init” target. <target name="test-cobertura:init" depends="cobertura:init"> <au:assertLogContains text="hello world !"/> <au:assertPropertyEquals name="cobertura.instrumented.classes.dir" value="${target}/coverage"/>
<au:assertPropertyEquals name="cobertura.datafile"
value="${cobertura.instrumented.classes.dir}/cobertura.ser"/> <au:assertPropertyEquals name="cobertura.include.classes.regex" value=".*"/> <au:assertPropertyEquals name="cobertura.exclude.classes.regex" value=".*\.Test.*"/> <au:assertPropertyEquals name="target.reports" value="${target}/reports"/>
<au:assertPropertyEquals name="target.coverage.reports"
value="${target.reports}/coverage"/> <au:assertPropertyEquals name="cobertura.src.dir" value="${src.main.java}"/>
</target>


Tests can be executed by running :

> easyant test

You can access test-reports at “target/antunit/html/index.html” or if you prefer the raw XML result “target/antunit/xml/TEST-src.test.antunit.cobertura-test_xml.xml”.

Ideally tests should emulate a fake project and verify cobertura reports are properly generated. But we will not cover it on this article.

The code of this plugin on GitHub.

### Project specific logic

In a previous article you have seen EasyAnt basics. This does the job most of the time but who has never needed custom logic in their projects ? This usually happens when you have project specific constraints or because a feature doesn’t exist yet in your favorite build tool.

Fortunatly, easyant offers solutions for both cases. The prefered way is to create reusable plugins, however sometimes we you only need it quickly on our project and don’t have time / money / motivation to spend on reusable stuff.

Project specific logic is implemented in an ant build file module.ant by default at same level of your module.ivy file.

 <project name="my-custom-stuff">
<echo>This message will be printed at startup </echo>
<target name="hello">
</target>
</project>

Invoking hello target will display our message.

 > easyant hello

Powerful isn’t it ? EasyAnt can print messages !

Ok you seem sceptical. This is useless if we can’t interact with existing targets in easyant.

## Depending on an existing target

First, you can depend on existing targets or extension points.

<target name="hello2" depends="package-jar:jar">
<echo>Hello world executed after package-jar:jar target </echo>
</target>

Invoking hello2 target will trigger package-jar:jar target and display our message. But if you invoke other target, hello2 target will never be called has no one depends on it.

This is what almost every one knows about ant. But ant provides a solution for this: Extension Point. Do you know what Extension point is ?

## Definition of Extension Point

Extension-Points are similar to targets in that they have a name and a depends list and can be executed from the command line. Just like targets they represent a state during the build process.

Unlike targets they don’t contain any tasks, their main purpose is to collect targets that contribute to the desired state in their depends list.

Targets can add themselves to an extension-points’s depends list via their extensionOf attribute. The targets that add themselves will be added after the targets of the explicit depends-attribute of the extension-point, if multiple targets add themselves, their relative order is not defined.

The main purpose of an extension-point is to act as an extension point for build files designed to be imported. In the imported file an extension-point defines a state that must be reached and targets from other build files can join the depends list of said extension-point in order to contribute to that state.

Original idea was from early stages of easyant is now part of Ant since 1.8.0.

## Integration of extensionPoint in EasyAnt

EasyAnt comes with a default lifecycle. This default lifecycle is a set of predefined extension points for the common needs.

Each phase is considered an essential step of the build process.

Note : Even if EasyAnt provides you a default lifecycle we never lock you in. So you’re able to add your own extension points or override existing ones.

Plugins can provide additionnal extension points. Plugins typically add low-level tasks to one or more extension-points. For example, a plugin can contribute to processing sources before compilation, you will in that case plug your own target to abstract-compile:compile-ready extension-point. This contributes to have a dynamic lifecycle.

When using easyant from the command line, you can use ProjectMan commands to get informations on available properties, targets or extensionPoints.
Invoking the following command will display available extensionPoints in your project.

> easyant -listExtensionPoints

## Depending on an existing extension point

Getting back to our example could we plug our hello target to compile step ?

<target name="hello3" depends="compile">
<echo>hello world displayed when compile extension point is reached</echo>
</target>

Calling any target depending on compile (part of the default lifecycle) will trigger hello3 target execution.

> easyant package

Will result :

...
[echo] This message will be printed at startup
...
...
compile-java:compile:
[mkdir] Created dir: /home/neoverflow/projects/easyant/community-plugins/projects/easyant-examples/project-specific-logic/target/main/classes
[javac] Compiling 1 source file to /home/neoverflow/projects/easyant/community-plugins/projects/easyant-examples/project-specific-logic/target/main/classes

hello3:
[echo] hello world displayed when compile extension point is reached

...
package-jar:jar:
[jar] Building jar: /home/neoverflow/projects/easyant/community-plugins/projects/easyant-examples/project-specific-logic/target/artifacts/project-specific-logic.jar

## Integrating a missing feature : Code Coverage

So now we’re done with theory, we know how extension points work in Ant. I need to solve a problem specific to my project: measuring the code coverage of my tests with cobertura.

How could we integrate cobertura ant task in our module.ant file easily ?

### Fetch cobertura and configure it

Usually this is done by copying manually cobertura.jar in $ANT_HOME/lib or in$USER_HOME/.ant/lib.

EasyAnt is based also on Apache Ivy therefore a quick search of cobertura on http://search.maven.org show us the ivy syntax to depend on cobertura.

<dependency org="net.sourceforge.cobertura" name="cobertura" rev="1.9.4.1"/>

But this is not a project dependency ! You don’t need it to package your project, you only need this dependency to run code coverage. Can ivy ant tasks help us here ? The answer is yes by using cachepath task. This task constructs an ant path consisting of artifacts in ivy cache for a resolved module.

Let us update our module.ant file to resolve the dependency, fill an ant classpath and configure cobertura.

<target name="cobertura:init">
<ivy:cachepath pathid="cobertura.classpath" inline="true" organisation="net.sourceforge.cobertura" module="cobertura" revision="1.9.4.1" conf="default" settingsRef="easyant.ivy.instance"/>
</target>

Note the presence of settingsRef attribute. EasyAnt uses two ivy instances :

• used to resolve/retrieve EasyAnt modules (which can be buildtypes/ plugins or skeletons) dependencies
• used to resolve/retrieve project dependencies

There is a strong separation of context, this means that plugins dependencies will not leak in your project. Both instance are configurable.

• Project ivy instance can be configured through an ivysettings file defined with properties. Click here if you want more details.
• EasyAnt ivy instance can be configured through an ivysettings file defined in easyant-config. Click here if you want more details.

### Perform coverage instrumentation

Now our problematic is to run coverage instrumentation, and integrate it with existing stuff in easyant.
Instrumentation needs to be done on compiled classes, so our task will depend on “compile” extension-point.

Then we could either “hardcode” some informations (path to compiled classes), or reuse easyant properties.
You can find all properties available in your project by using the following ProjectMan command :

> easyant -listProp

So here we will reuse the following properties / classpath

• Property : target.test.classes
• Property : target.integration.test.classes
• Path : run.test.classpath
<target name="cobertura:instrument" depends="cobertura:init,compile,abstract-test:init">
<property name="coverage.dir" value="${target}/coverage"/> <property name="coverage.datafile" value="${coverage.dir}/cobertura.ser"/>
<mkdir dir="${coverage.dir}"/> <!-- delete previous coverage data file --> <delete file="${coverage.datafile}" />

<!-- do instrumentation -->
<cobertura-instrument todir="${coverage.dir}" datafile="${coverage.datafile}">
<fileset dir="${target.test.classes}"/> <fileset dir="${target.test.integration.classes}"/>
</cobertura-instrument>

<!-- contribute to test runtime classpath and prepend instrumented classes -->
<ea:path pathid="run.test.classpath" overwrite="prepend">
<fileset dir="${coverage.dir}"/> </ea:path> </target> ### Do reporting <target name="cobertura:run" depends="cobertura:instrument"> <cobertura-report format="html" destdir="${target.report.dir}" srcdir="${src.main.java}" datafile="${coverage.datafile}"/>
</target>

That’s all, you’re now able to run code coverage in your project.

You can find the code of this example with project specific logic on GitHub.

Next article : We will refactor or module.ant to create a cobertura plugin.

### Getting started with EasyAnt

In the course of this write up, you will be taken through basics of EasyAnt and a simple-and-live example of setting up an EasyAnt web application project. Prerequisite to your setting up an Easyant project means you have to have the Easyant environment correctly configured. The only thing you need to do to use easyant is to set the EASYANT_HOME property.

You should first set up in your environment the EASYANT_HOME variable :

• for windows users : set EASYANT_HOME=c:\path\to\easyant
• for unix users : export EASYANT_HOME=/path/to/easyant

• for windows users : set PATH=%EASYANT_HOME%\bin;%PATH%
• for unix users : export PATH=$EASYANT_HOME/bin:$PATH

Let us try to setup a java Web Application project.

EasyAnt provides skeleton feature to quickstart projects. It basically creates a projects structure, based on an existing model. You can fortunatly create your own skeleton but we will cover this in future articles.

Selecting available skeleton :

> easyant skeleton:select
-skeleton:select:
[echo] Choose a skeleton in the following list:
[ea:searchmodule] 1: std-skeleton v0.9 (Emtpy skeleton structure)
[ea:searchmodule] 2: std-java-application v0.9 (Skeleton for creating standard java application)
[ea:searchmodule] 3: std-ant-plugin v0.9 (Skeleton for creating ant based plugin for easyant)
[ea:searchmodule] 4: std-java-webapplication v0.9 (Skeleton for creating standard java web application)
[ea:searchmodule] Choose a number: (1, 2, 3, 4)

std-java-webapplication is what we are looking for, now it’s time to answer a few questions :


[input] The path where the skeleton project will be unzipped [.]

[input] Organisation name of YOUR project []
org.mycompany
[input] Module name of YOUR project
myproject
[input] Revision number of YOUR project [0.1]

Few seconds later we have our project ready to use.

Note: organisation, module, and revision terminology comes from Apache Ivy.

A project using EasyAnt MUST contain a file named module.ivy and an optional file named module.ant.

## The module.ivy file

This file is the module descriptor of your project. It contains information like your company name, the module name, dependencies, and Easyant build information. This is nearly a regular IVY specification file.

<ivy-module version="2.0" xmlns:ea="http://www.easyant.org">
<info organisation="my.easyant.project" module="my-webapp" status="integration" >
<description>
This project is a sample of a java webapplication
</description>
<ea:build organisation="org.apache.easyant.buildtypes" module="build-webapp-java" revision="0.9"/>
</info>
<configurations>
<conf name="default"/>
<conf name="test" />
</configurations>
<publications>
<artifact type="war"/>
</publications>
</ivy-module>

The above is a standard ivy specification file, other than the ‘ea:build’ tag. To use easyant you must declare the easyant namespace

xmlns:ea="http://www.easyant.org"

Pay attention to the ea:build tag. This tags define which build-type is used for your project. In our case, we intend to set up a standard war so we will use build-webapp-java which provides all the targets necessary to compile / package a webapp application.

Note: The organisation argument in ea:build tag is optional. If not specified easyant will use the default one (org.apache.easyant.buildtypes).

The above file is a sufficient instruction to easyant to build a WAR using the current project. Only, you need to mind the source structure for this build to work.

## Source Structure

Similar to Maven, by default, if you are using a standard build type, you need to follow a standard directory structure. This should be as the build type expects to pick different resources to be present in different directories.

Use the following:

In the above directory structure, all your java sources should go into src/main/java directory. All resources that should move into WEB-INF/classes directory should go inside src/main/resources. Entire src/main/webapp directory moves into the root of the web application WAR. For instance, you may keep WEB-INF directory inside this directory. The module.ivy file should reside inside ‘testproj’ directory. Any external dependencies of your project should be specified inside your module.ivy file, dependencies section.

## Building the Project

The project is now ready to be built. You can simply run: easyant. You should see a ‘target’ directory created in your project root. The built war will reside inside the target/artifacts directory. You can go ahead and deploy it in your app-server.

### Running default target

Running easyant without arguments will execute the default target of a project.

Example :

> easyant

### Running a specific extension point

Running EasyAnt with a extension point name will execute ALL the targets bound to it.

Example:

> easyant package

All targets related to the package extension point will be executed. Supposing your build is composed of several modules that generate packages (jar + source.jar + documentation.jar). All such packages will be generated. If your need is just to create the first jar, maybe you should call the explicit target instead.

### Running a specific target

Running EasyAnt with a target name or a list of names will execute only the specified targets.

Example:

> easyant package-jar:jar

### Displaying project help

Running EasyAnt with “-p” argument will display a project help (ie. show all extension point / target available)

Example:

> easyant -p

Dependencies are defined in the module.ivy files. There is a section dedicated to dependencies Let’s consider that our project needs an artifact named foo provided by acme in revision 2.0 The dependencies section will look like this :

<dependencies>
<dependency org="acme" name="foo" rev="2.0" conf="default"/>
</dependencies>

Almost everything is configurable through properties in easyant. Suppose we want to have the generated artifacts in “dist” directory instead of “target/artifacts”. We will add additional informations :

<ea:build organisation="org.apache.easyant.buildtypes" module="build-std-java" revision="0.9"/>
<ea:property name="target.artifacts" value="dist"/>
</ea:build>

Running “easyant” will generate the output war in “dist” directory.
Now we want to force java 1.5 compatibility at compile time. We will add additionnal property :

<ea:build organisation="org.apache.easyant.buildtypes" module="build-std-java" revision="0.9"/>
<ea:property name="target.artifacts" value="dist"/>
<ea:property name="compile.java.target.version" value="1.5"/>
</ea:build>


EasyAnt provides plugins that you can selectively choose to use in your project. These provide you convenience functionalities. E.g. Quick WAR deployments in Jetty, Xooki documentation, Coverage tools etc. In this tutorial, let us quickly take a look over how we may integrate Jetty with our current war. Let us first include a ‘Hello World’ index.htm inside the src/main/webapp directory. These are the contents of our index.htm:

<html>
<body>
<h3>Hello World !!</h3>
</body>
</html>

Our module.ivy is the repository of all plugins that our project uses. So, we go ahead and include the Jetty plugin in our module.ivy.

<ivy-module version="2.0" xmlns:ea="http://www.easyant.org">
<info organisation="my.easyant.project" module="my-webapp" status="integration" >
<description>
This project is a sample of a java webapplication
</description>
<ea:build organisation="org.apache.easyant.buildtypes" module="build-webapp-java" revision="0.9">
<ea:plugin organisation="org.apache.easyant.plugins" module="jetty-deploy" revision="0.9"/>
</ea:build>
</info>
<configurations>
<conf name="default" />
<conf name="test" />
</configurations>
<publications>
<artifact type="war"/>
</publications>
<dependencies>
<dependency org="acme" name="foo" rev="2.0" conf="default"/>
</dependencies>

</ivy-module>`

Note the addition of the ea:plugin tag. The above line instructs easyant to use the jetty-deploy plugin in version 0.9 in the current project.

Note: The organisation argument in ea:plugin tag is optional. If not specified easyant will use the default one (org.apache.easyant.plugins).

The jetty-deploy module exposes a target called ‘jetty-deploy:run’. Further, this target depends on package-war:war of EasyAnt, which means that by the time this target is executed, the WAR would have been created and available for deployment on Jetty. Because, in the new line added to module.ivy, the jetty-deploy module was added you can run ‘easyant jetty-deploy:run’ to build and package your web application, and deploy it on jetty. The command launches jetty, and keeps displaying Jetty logs on console. You can now access your web application on browser. Try hitting http://localhost:8080 !

## module.ant

If you want to add something to the default build types that come packaged with EasyAnt, you can write a module.ant file in your project root. This is called before EasyAnt executes any of its core build scripts. You can also include any convenience targets you find useful, that are specific to your project and do not come included in EasyAnt. This will be covered in future article.