This is a Very Special Guest Post by Jim Moores, another one of the OpenGamma team. We thought this would be useful to the interwebs, and until we have the OpenGamma blog ready to go, we're all ranting as one.
Ivy is a great way of avoiding shipping all the dependent libraries with
your code and making upgrading dependencies smoother and easier, but it can
still be a bit rough around the edges. For those of you new to Ivy, it's a
dependency manager that is built on top of
Ant that goes off and downloads
and installs all your dependent libraries given a pretty simple list in an
xml file. It hit version 2.0 a few months back and started to be really
useful with more and more projects switching over to it. Of course Maven
has done many of the same things for much longer, but Ivy doesn't require
the whole head-warping change of viewpoint that Maven does. To be fair to
Maven, I've only used it in passing when building the MyFaces JSF source
code and while I did get it working, and was impressed, it took a bit of
fiddling. My general understanding of Maven is that it's more declarative
than 'normal' build systems - you tell it what you need and you have to rely
on it figuring the whole thing out and it requires you let go of the idea of
targets and explicit flow control (apologies to Maven fans if any of this is
inaccurate). Ivy requires less of a leap of faith because it fits in with
the Ant style that is more familiar to many but still brings the advantages
of automatic dependency tracking. It can even install itself.
When I first tried Ivy three or four months ago I quickly found that some of
the packages I wanted weren't available in the default ibiblio maven
repository, in my case it was BerkeleyDB. I soon came across the excellent
Ivy RoundUp repository. Ivy RoundUp doesn't actually host the packages
themselves, it's a meta-repository that hosts information on how to download
extract and repackage artifacts on demand. Unfortunately I couldn't just
switch over to RoundUp because I needed some packages that were only on
ibibio, so I had to delve deeper into the ivysettings.xml file to set up
what is called a chain resolver. Chain resolvers do just what they sound
like they do - they try one repository and then fall back to another if the
package can't be found in the first. Here is my settings file:
Unfortunately this didn't work at all. It turned out that the example ivy
build.xml in the tutorial contains the line:
<property name="ivy.install.version" value="2.0.0-beta1">
</property>
And that 2.0.0-beta1 has a bug in it that means that chain resolvers don't
work. Once I updated the
ivy.install.version
property to the latest version (
2.0.0
at the time) it worked fine.
This is still a problem with the tutorials, so be aware.
Since then I've needed to start using Hibernate in my application so I
thought adding it would be easy as it's one of the most widely used Java
packages. Err, no. After finding Hibernate in RoundUp easily enough (the
latest ibibio version is really old), my build hung for some time,
apparently unpacking a file, and then went totally exception-tastic on me.
[ivy:cachepath]
[ivy:cachepath] download.1.N65558:
[ivy:cachepath]
[ivy:cachepath] [get] Getting: file://C:/DOCUME~1/Jim/LOCALS~1/Temp//jta-1_1-classes.zip
[ivy:cachepath]
[ivy:cachepath] [get] To: C:\Documents and Settings\Jim\.ivy2\packager\cache\jta-1_1-classes.zip
[ivy:cachepath]
[ivy:cachepath] [get] Error getting file://C:/DOCUME~1/Jim/LOCALS~1/Temp//jta-1_1-classes.zip to C:\Documents and Settings\Jim\.ivy2\packager\cache\jta-1_1-classes.zip
[ivy:cachepath]
[ivy:cachepath] C:\Documents and Settings\Jim\.ivy2\packager\build\javax.transaction\jta\1.1\build.xml:53: The following error occurred while executing this line:
[ivy:cachepath] C:\Documents and Settings\Jim\.ivy2\packager\build\javax.transaction\jta\1.1\packager-output.xml:28: java.net.UnknownHostException: C
[ivy:cachepath] at org.apache.tools.ant.ProjectHelper.addLocationToBuildException(ProjectHelper.java:541)
[ivy:cachepath] at org.apache.tools.ant.taskdefs.Ant.execute(Ant.java:418)
[ivy:cachepath] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
[ivy:cachepath] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[ivy:cachepath] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[ivy:cachepath] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
and another ten pages of related stuff which I'll spare you. There was
clearly some problem in downloading the JTA 1.1 classes, which are a
dependency of Hibernate. I tried upgrading to the latest version of ivy -
didn't work. I then assumed it was an ivy package file and went digging
around. When I looked to see the temporary file it was trying to open it
wasn't actually there. Hmm. Just before that it implies that it's
downloading the file in question. Could it be deleting it? I eventually
decided it must be a problem with the file in the repository, so I went
looking for help there. That's when I came across
this thread on the
roundup mailing list archives, and then onto
the Roundup discussion of manually downloaded software.
It seems some of the software
DOES NOT get downloaded automatically by ivy.
Unfortunately, instead of giving you a nice error message telling you where
to put it, you get a
java.net.UnknownHostException
. It turns out you need
to download the artifacts manually from the Sun website and put them in the
temporary directory ivy uses to store package downloads.
Once it did this it all works magically. Apparently the reason for this is
that the download requires ticking a license agreement box which can't be
done automatically. I hope this knowledge helps someone save some time. I
think in the long run it'll probably mean me having a private repository for
those artifacts, but for now I'll leave that for another day.