Tuesday, January 27, 2009

Java WebStart success?

Just maybe, I'm on the verge of success gaining the Holy Grail: automatic continuous integration of a Java WebStart application! What are the pieces?
  • Maven and Ant
  • Artifactory
  • Hudson
  • Jetty
  • JNLP servlet
Whew! Some details on each piece...

Ant and Maven
I like Maven for the convention it brings (as in Convention over Configuration). The repositories and versioning of dependencies are wonderful. The bad news is that a WebStart application isn't the traditional JAR or WAR build that Maven knows about. (N.B. - I may come back to this, since using the JNLP servlet, it *could* be a WAR file.) The good news would seem to be that of course, there a couple plugins that do neat WebStart things - including building the JNLP file from the dependencies. You know, DRY! The first one from CodeCrate offers great promise - handle the simple case! Cool. Well, it's a fail straightaway since it can't seem to find the dependencies at all and gets a ClassNotFoundExeception. Bummer. So I go for the full Monty - Maven Webstart Plugin . There's a "cookbook recipe" which shows a "Getting started" page. But no examples for the simple case - they go straight to WAR bundles. :( And the Maven jar signing plugin will only sign the main artifact - not all the dependencies. Double fail.
Ant to the rescue! Fortunately, Ant knows how to sign jars and Hudson will run multiple steps in the build, so it is easy to mix Ant and Maven. Ant will sign the dependency jars and Maven will build the rest of the project. The only loss is not generating the JNLP from the dependencies.

Artifactory, Hudson and Jetty
Both of these are handy web-based tools. Each is easy to install and configure - UNLESS you want password protection. My first thought is to bundle both into a Tomcat instance. Should be easy enough - both give instructions on that. Password protecting Tomcat sites should be easy enough. OK, start with Artifactory. Endless headaches, fails, NullPointerException, etc. Finally come across a suggestion to never use pre-installed Tomcat instances on Linux boxes. Oh! OK - download and install Tomcat 6.0.18 - works great! The password protection works. Now, just have to add the Hudson webapp. FAIL - OutOfMemoryError out the gazoo. Having used Jetty before with good success, I revert to separate Jetty installations - one for Artifactory, one for Hudson. Even with password protection!

JNLP Servlet
Providing links to a JNLP file and having it link all its resources works fine. Just one problem: the JNLP has the codebase in it, so at build/deploy time you have to know where you're deploying to. A bit of a problem if you want to build and deploy to a test server, then promote to production. But wait, the JNLP Servlet to the rescue: it filters the JNLP and drops in the proper codebase for you. Nice! Now let's see - where's the JNLP servlet?
The JnlpDownloadServeltGuide from the Sun JavaSE 6 TechNotes says: "The servlet is packaged into the jnlp-servlet.jar file, which can be found in the SDK under samples/jnlp/servlet/" OK - I've got lots of JDK/JRE installations.
find /usr/java -name samples
Nothing. Hmm... Oh, update 11 is out - let's download that. And there's a nice document in the Java Web Start Reference pages called "Packaging JNLP Applications in a Web Archive" - sweet. That's interesting, there's a "sample" directory in this JDK. Oh, even a "jnlp" directory under that. Cool - cooking with gas now. Follow all the instructions about deploying, etc. FAIL - java.lang.ClassNotFoundException: com.sun.javaws.servlet.JnlpDownloadServlet
jar -tvf WEB-INF/lib/jnlp-servlet.jar
Oh look! All of them are "jnlp.sample" package, not "com.sun.javaws"! Thanks a lot. So change the servlet definition in the web.xml. Finally - success!

The only remaining piece is to have Maven or Ant copy the proper files to the Jetty webapp directory. How hard can that be?