Tuesday, August 25, 2009

Ant, Ivy 2.0.0, and java.net.UnknownHostException

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">
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] download.1.N65558:
[ivy:cachepath]       [get] Getting: file://C:/DOCUME~1/Jim/LOCALS~1/Temp//jta-1_1-classes.zip
[ivy:cachepath]       [get] To: C:\Documents and Settings\Jim\.ivy2\packager\cache\jta-1_1-classes.zip
[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] 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.

blog comments powered by Disqus