From time to time I read about an interesting Java project and would like to try it. For example Apache Jackrabbit, a library implementing JSR 170 (Java Content Repository). But setting up the my Java environment to run the examples is a hassle because of the many libraries required. Over time I got better at starting new projects: I have project snapshots that contain all the Eclipse and Ant artifacts for a simple application with proper JUnit tests and logging. Still, downloading all required libraries in the proper directories and updating Ant and Eclipse configuration is a drag. There must be a better way to do it other than downloading manually libraries from various sites. In this context I decided to try Apache Ivy with the recently released version 2.0.0.
Ivy is a dependency manager oriented toward Java dependency management. Conceptually, it is based on the idea that an application needs artifacts that are available in repositories. There is a hierarchy of repositories (local, shared, public). Ivy will search for each artifact in these repositories. For my quick/experimental Java projects I use only the ibiblio public repository (artifacts hosted at http://repo1.maven.org/maven2). A powerful feature is the handling of “transitive dependencies:” Ivy gets not only the required artifact but also all the artifacts it depends on.
After the jar files are stored in the work area, how do they get in Ant and Eclipse? Ivy is well integrated with Ant. It has tasks to retrieve artifacts and to update an ant variable with the correct jar names so that it can be used in javac task as classpath. For Eclipse, there is a plug-in called Apache Ivy IDE which adds all the files identified by Ivy as required in the project library.
In the case of Apache Jackrabbit, the Ivy file (ivy.xml) is:
<ivy-module version="2.0"> <info organisation="intspc" module="jackrabbit"/> <dependencies> <dependency org="log4j" name="log4j" rev="1.2.14"/> <dependency org="junit" name="junit" rev="3.8.1"/> <dependency org="org.apache.jackrabbit" name="jackrabbit-api" rev="1.4"/> <dependency org="org.apache.jackrabbit" name="jackrabbit-core" rev="1.4"/> <dependency org="org.apache.jackrabbit" name="jackrabbit-jcr-commons" rev="1.4"/> <dependency org="org.apache.jackrabbit" name="jackrabbit-spi" rev="1.4"/> <dependency org="org.apache.jackrabbit" name="jackrabbit-spi-commons" rev="1.4"/> <dependency org="commons-collections" name="commons-collections" rev="3.1"/> <dependency org="org.apache.derby" name="derby" rev="1.2.1.6"/> <dependency org="concurrent" name="concurrent" rev="1.3.4"/> <dependency org="org.slf4j" name="slf4j-simple" rev="1.3.0"/> </dependencies> </ivy-module>
The Ant task for setting the build.classpath variable that is used in the compile target:
<target name="init" description="--> retreive dependencies with ivy">
<ivy:settings file="ivysettings.xml" />
<ivy:resolve/>
<ivy:cachepath pathid="build.classpath" />
</target>
....
<target name="compile" depends="init, prepare">
<javac srcdir="main/java" debug="true" destdir="${main.classes.dir}" deprecation="true" includeAntRuntime="no">
<!-- compilerarg value="-Xlint:unchecked"/ -->
<classpath refid="build.classpath" />
<include name="**/*.java" />
</javac>
</target>
The Eclipse library is displayed in the image on the right. Notice that there are more jars in the library than artifacts mentioned in the Ivy file. The extras are the dependencies. The Eclipse library was built by the Apache Ivy IDE 2.0.0 beta.
To speed-up the next experimental projects I updated my project template to take advantage of Ivy:
-
added Ivy library to the Ant lib directory. I can now easily use Ivy in build.xml without taskdef and other settings
-
created the file ivy.xml in the root of the project template. It contains at this time only log4j and junit. Each project will add its own libraries.
Not all the interesting libraries are in the default public repository (http://repo1.maven.org/maven2). For those cases, the project needs a ivy settings file (ivysettings.xml) that points to the public repositories which holds the artifact. The example below shows how to add the public repository http://download.java.net/maven/2.
<ivysettings> <settings defaultResolver="chained"/> <resolvers> <chain name="chained" returnFirst="true"> <filesystem name="libraries"> <artifact pattern="${ivy.conf.dir}/repository/[module]/[artifact]-[revision].[type]" /> </filesystem> <ibiblio name="ibiblio" m2compatible="true"/> <ibiblio name="java-net-maven2" root="http://download.java.net/maven/2/" m2compatible="true"/> </chain> </resolvers> </ivysettings>
And there are situations when there is no public ivy-repository for a package. For those cases, I created a “shared” repository and added a new resolver in Ivy settings:
<ivysettings>
...
<resolvers>
<chain name="chained" returnFirst="true">
<filesystem name="jlib">
<artifact pattern="${jlib.home}/[module]/[artifact]-[revision].[type]" />
</filesystem>
...
</chain>
</resolvers>
</ivysettings>
Other ideas:
-
setup a Shared repository and add to it the commercial libraries that are available to the organization
-
add the ability to publish artifacts in the Shared repository for cross-project dependencies
-
retrofit existing projects to use Ivy rather than relying on a shared folder for dependent libraries
-
revise the deployment model of Java applications, in the context of using Ivy to manage external dependencies.
-
Ivy does not have to be about Java jar files. Any artifact dependency can be expressed using Ivy. How can this be used for managing other software/project artifacts?
Related links:
-
Apache Ivy: http://ant.apache.org/ivy/
-
Apache Ivy IDE: http://ant.apache.org/ivy/ivyde/
-
Article on IBM developerworks about Ivy: http://www.ibm.com/developerworks/java/library/j-ap05068/index.html
Updates:
- 2010-04-01 – The source code for a sample project that uses Ivy is available online at: http://www.integrationspace.com/repository/intspc/ivydemo/1.0a/ivydemo-1.0a-src.zip. Unzip the file and run the command “ant junit”. It shows how Ivy resolves dependencies and how ant integrates with ivy to build and run unit tests.
No Comments
No comments yet.