Do you appreciate the Maven style of downloading all 3rd party JARs automagically, but don't admire the rest of it? Then this Ant task is for you!
How do you manage 3rd party JARs today? Do you store them together with the sources in your VCS? Don't do that! It's a waste of space, imagine 20 in-house projects were all are using log4j.jar (345KB x 20 ~ 7MB). Then you decide to upgrade from version 1.2.7 to 1.2.8. You got the point! Numerous JARs in a VCS system also slow downs the overall operation speed of the server. So, the best you can do is to keep the 3rd party JARs outside your version control system. However, it's cumbersome, and still waste of space, to manage many different JARs in a private file filesystem. It is also tedious to manage a shared directory, because it's not always appropriate to map drive letters and it might not perform good as well. I have extensive experience of both cases described, which led to investigation and later rejection of Maven. I felt I wasn't willing to sacrifice my taste of project organization, and jump onto the Maven bandwagon. The end result is this very small Ant task, that provides a Maven style download service, as well as an upload service to publish your own artifact.
This Ant task provies a download task, that accepts a nested list of dependency definitions, together with one or more repository definitions. When the task is executed all dependecies are resolved into URLs and downloaded from one of the repositories, into a cache directory. Dependencies can be defined in an external xml file, given as a file path or as a class path resource.
In addition, there is also an upload task that given one dependency definition and one repository, copies an artifact (JAR/WAR/EAR/ZIP/...) file into the repository.
This Ant task provides a Maven style downloading service, by declaring a set of dependencies. Files corresponding to dependencies are downloaded from a repository. The snippet below shows a small example.
<download id="foo" dir="${build.dir}/cache">
<mavenrepository url="http://www.ibiblio.org/maven/"/>
<dependency>
<id>JakartaBeanUtils</id>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.6.1</version>
</dependency>
</download>
The task downloads the beanutils jar from the official Maven repository (ibiblio)
and stores it into the cache directory (${build.dir}/cache) as the file
JakartaBeanUtils.jar. No download will take place if the file
already is present in the cache.
The id attribute of the task defines a pattern set that later might be used in a fileset or another Ant type that supports pattern sets.
<war destfile="${dist.dir}/foobar.zip" webxml="...">
<lib dir="${build.dir}/cache">
<patternset refid="foo"/>
</lib>
...
</war>This Ant task performs the opposite of the download task. Given an artifact file, a repository and a dependency defintion, it copies the file into the repository using the dependency defintion to create the artifact path/url. The snippet below shows a small example.
<upload file="${dist.dir}/myFoobar.war">
<localrepository dir="R:/mavenrepo"/>
<dependency>
<id>myFoobar</id>
<groupId>com.myCompany</groupId>
<artifactId>myFoobar</artifactId>
<version>1.2.3</version>
<type>war</type>
</dependency>
</upload>The file 'myFoobar.war' is copied to R:/mavenrepo/com.myCompany/wars/myFoobar-1.2.3.war. if the directory is web enabled as well, then the artifact is available at an URL similar to 'http://www.myCompany.com/mavenrepo/com.myCompany/wars/myFoobar-1.2.3.war'.
A download task contains one or more dependency definitions. A dependency definitions is 'mostly' compatible with a Maven dependency definition. A dependency have a set of properties, expressed as attributes or nested elements (maven style). See the table below for a list of available properties.
A download task contains one or more repository definitions. A repository is either remote (http) or local (directory). The former is called a 'mavenrepository' and the latter is called 'localrepository'. A maven repository takes an url attribute specifying the root of its artifact tree. A local repository takes a directory attribute specifying the root of its artifact tree. If neither, a maven nor a local repository is appropriate, you can implement your own and supply its class name to a 'customrepository' definition.
A download task, might refer to an external xml file containing dependency definitions. The file can reside in the file system (attribute file) or inside the class path (attributes resource/classpath). This external file must nest all dependencies inside a 'dependencies' parent node. This node might be the root node of the xml file (stand-alone) or be a child of a 'project' root (maven project file).
This library has been developed and tested with Ant 1.6 and JDK 1.4.2. It's using some Ant 1.6 features, however I'm haven't investigated if it runs on an older JDK than 1.4.
Download and unpack the distribution, and copy the libray JAR file to a convenient directory. Add the task using Ant's 'taskdef' and antlib support. Here is an example of a 'build.xml' snippet.
<typedef resource="com/ribomation/dependencies/ant/antlib.xml">
<classpath>
<pathelement location="${lib.dir}/dependencies-2.0.jar" />
<pathelement location="${dom4j.dir}/${dom4j.jar}"/>
</classpath>
</typedef>
The "quick and dirty" installation uses Ant's own download support. Copy the XML snippet below to your own 'build.xml'. Change the download directory (lib.dir) to something appropriate for you. If the JAR file is not available, in the class file it is downloaded from the remote repository.
<path id="deps.classpath">
<pathelement location="${cache.dir}/${deps.jar}"/>
<pathelement location="${dom4j.dir}/${dom4j.jar}"/>
</path>
<target name="deps.check">
<available
property="deps.class.available"
classname="${deps.class}"
classpathref="deps.classpath"/>
</target>
<target name="deps.download" depends="deps.check" unless="deps.class.available">
<mkdir dir="${cache.dir}"/>
<get src="${repo.url}/${deps.path}/${deps.jar}" dest="${cache.dir}/${deps.jar}" />
</target>
<target name="deps.setup" depends="deps.download">
<typedef resource="com/ribomation/dependencies/ant/antlib.xml">
<classpath refid="deps.classpath"/>
</typedef>
</target>
<target name="cache.download" depends="deps.setup">
<download id="libs" dir="${cache.dir}">
<mavenrepository url="${repo.url}"/>
<dependency id="junit" version="3.8.1"/>
</download>
</target>
The Ant properties used in the snippet above, is listed below (taken from build.properties).
repo.url = http://www.ribomation.com/mavenrepo
deps.path = com.ribomation.dependencies/jars
deps.version = 2.0
deps.jar = dependencies-${deps.version}.jar
deps.class = com.ribomation.dependencies.ant.DownloadTask
dom4j.dir = C:/java/libs/dom4j-1.5
dom4j.jar = dom4j-1.5.jar
This section describes all elements and their attributes.
| Attribute | Required | Description |
|---|---|---|
| id | Yes | Defines a pattern set of the downloaded files. |
| dir | Yes | Cache directory, i.e. where to store downloaded files. |
| file | No | Name of external dependencies xml file. This file contains a set of dependency definitions having a 'dependencies' node as their parent. This node might be the root (stand-alone) or nested inside a 'project' root (Maven POM). |
| resource | No | Name of external dependencies xml, inside the class path. Same file structure as for attribute 'file'. |
| classpathref | No | Class path to use in combination with attribute 'resource'. |
The search for a file to download is performed in the same order repositories are listed. Supported repositories are listed in the table below.
| Name | Attribute(s) | Description |
|---|---|---|
| mavenrepository | url - Url to root of remote/web Maven repository. | Classic Maven remote repository. |
| localrepository | dir - Path to root of local/directory Maven repository. | Maven repository in your own file system. |
| customrepository | classname - Name of class implementing interface com.ribomation.dependencies.Repository | Takes nested <param name="msg">hello</param> elements for JavaBean style configuration of the custom repository. In addition, this element supports attribute 'classpathref' and nested element 'classpath', with their usual Ant behaviour. |
The dependency nested element is a container for the properties listed in the table below. Properties might specified as nested elements (Maven style) or as attributes.
| Property | Required | Default | Description |
|---|---|---|---|
| id | Yes | Unique id. | |
| groupId | No | value of id | Typical a package name or similar. |
| artifactId | No | value of id | (Base)name of the file |
| version | No | 1.0 | Its dotted version. |
| type | No | jar | Its file type, like 'jar', 'war'. Default is 'jar'. |
| url | No | URL to the web site for manual download and more info. |