Java jar dependency management using Ivy

Along with our source code, we’ve also been putting all required jars into cvs, basically for two reasons:

  • The build process controlled by cruisecontrol needs the jars, but cruisecontrol runs on a server where we don’t want to install an IDE (jdeveloper). We’ve put all adf, bc4j and other required jars into cvs, and when the build process compiles the application, it first gets all the required source code and the required jars, so no need for jdeveloper.
  • We want version control on dependencies. If you check out the code for release 1, you need the jars that release 1 depends on. If you check out release 2, you will need different jars.

So just relying on the project dependencies in jdeveloper is not an option.

The downside to this approach however, is that we get a lot of jars in cvs, and many projects use the same jar files, so it’s bit of a waste. For some time, i thought the solution would be to move from using ant to using maven for building the code. However, some weeks ago, i discovered ivy. Ivy is a java dependency manager, which you can easily use in existing projects using ant.

I’ve just added ivy to our first project. Below i’ll describe the steps to implement dependency management using ivy.

I’ve added the following target to all our ant build files. It gets all the required jar files and stores them in a lib directory in your project. You need to put this before the target which compiles your code.

  <target name="resolve.dependencies">
	<taskdef name="ivy-retrieve"
	                 classname="fr.jayasoft.ivy.ant.IvyRetrieve">
	  <classpath refid="classpath"/>
	</taskdef>
	<ivy-retrieve pattern="${ivy.lib.dir}/[artifact].[ext]"/>
  </target>

Next step: I’ve added a new workspace and project in jdeveloper which acts as a jar repository for all for all projects. On the cruisecontrol server, this workspace is also checked out of cvs, and the ivy target described above, copies the jar files from this jar repository. The file structure of this workspace is as follows:

./oracle
./oracle/bc4j
./oracle/bc4j/10.1.2
./oracle/bc4j/10.1.2/bc4jct.jar
./oracle/bc4j/10.1.2/bc4jhtml.jar
./oracle/bc4j/10.1.2/bc4jmt.jar
./oracle/bc4j/10.1.2/ivy.xml
./oracle/adf
./oracle/adf/10.1.2
./oracle/adf/10.1.2/adf-controller.jar
./oracle/adf/10.1.2/adfm.jar
./oracle/adf/10.1.2/ivy.xml
...

As you can see, it contains all the jar files used by other projects. Every directory also contains an ivy.xml file which describe the dependencies of the jars in that directory.

For example, the ivy.xml file in the adf directory looks like this:

<ivy-module version="1.1">
  <info organisation="oracle" module="adf" revision="10.1.2" status="release"/>
  <publications>
	<artifact name="adfm" type="jar"/>
	<artifact name="adftags" type="jar"/>
	<artifact name="adf-controller" type="jar"/>
  </publications>
  <dependencies>
	<dependency org="apache" name="commons-el" rev="1.0">
	  <artifact name="jsp-el-api" type="jar"/>
	  <artifact name="commons-el" type="jar"/>
	</dependency>
	<dependency org="sun" name="servlet" rev="2.3"/>
	<dependency org="oracle" name="jsp-el" rev="1.0">
	  <artifact name="oracle-el" type="jar"/>
	</dependency>
	<dependency org="oracle" name="bc4j" rev="10.1.2">
	  <artifact name="bc4jmt" type="jar"/>
	  <artifact name="bc4jct" type="jar"/>
	  <artifact name="bc4jhtml" type="jar"/>
	  <artifact name="bc4jdomorcl" type="jar"/>
	</dependency>
	<dependency org="apache" name="struts" rev="1.1"/>
	<dependency org="apache" name="commons-beanutils" rev="1.6.1"/>
	<dependency org="sun" name="collections" rev="1.0"/>
	<dependency org="oracle" name="jdev" rev="10.1.2">
	  <artifact name="jdev-rt" type="jar"/>
	</dependency>
	<dependency org="sax" name="sax" rev="2.0.1"/>
  </dependencies>
</ivy-module>

So it specifies that the adf libraries depend on sax.jar, jdev-rt.jar, and some other libraries. In your application project you only have to specify that your application depends on adf, and ivy will automatically download the adf jars and any jars required by adf.

Next, i had to specify the dependencies of my application. The following ivy.xml file describes the dependencies of a view controller project build using adf, bc4j, jsp’s and struts:

<ivy-module version="1.0">
  <info organisation="nl.iteye" module="ViewController"/>
  <dependencies>
	<dependency org="hunsicker" name="jalopy-ant" rev="0.6.1"/>
	<dependency org="apache" name="struts" rev="1.1"/>
	<dependency org="sun" name="servlet" rev="2.3"/>
	<dependency org="oracle" name="jdev" rev="10.1.2">
	  <artifact name="ojmisc" type="jar"/>
	  <artifact name="jdev-rt" type="jar"/>
	  <artifact name="jdev-cm" type="jar"/>
	</dependency>
	<dependency org="oracle" name="bc4j" rev="10.1.2">
	  <artifact name="bc4jhtml" type="jar"/>
	</dependency>
	<dependency org="apache" name="struts" rev="1.1"/>
	<dependency org="oracle" name="adf" rev="10.1.2">
	  <artifact name="adf-controller" type="jar"/>
	  <artifact name="adftags" type="jar"/>
	</dependency>
  </dependencies>
</ivy-module>

That’s about it. Creating the repository containing the jar files, and the ivy.xml files describing their dependencies takes some time. A great help here is the jarjar tool.

blog comments powered by Disqus