For the last few days I've been trying to get an application to work with Java WebStart included with the JDK 1.6.0. It's been challenging, and what I've learned is that there's a lot you can do, and a lot you can't, and the trick is trying to turn the things you can't into things you can.
Packaging Shared Libraries
One of the things that isn't too hard to figure out is how to get shared libraries (so or dll) down to the client. Basically, you put them in a jar file and then sign that bad boy. There is one thing I learned: Sign all jars with the same key. The JWS is picky that way - they have to be the same key.
Delivering XML Files
Say you have an application (like I do) that uses XML files to configure itself properly. I didn't really pick this behavior, but it's something that I can see people dealing with. The Java code needs to be given the path to these XML files as arguments to the program, and then within the program it reads these XML files and deals with their contents. The problem is two-fold: getting the XML files there, and referencing their location.
Seems silly, but it's something I just lucked into. I had the XML files in a directory called cfg, and so I created a jar file with the cfg directory in it - just a bunch of XML files, and then signed that jar and placed it in the jnlp file as a nativelib resource. Something like this:
<resources>
<nativelib href="lib/cfg.jar" />
</resources>
where I have ended up placing all my jar files in the lib subdirectory of the root of the JWS location. Then, if I use the arguments to the app indicating the location of the XML files are simply cfg/startUp.xml then the app will find them. Amazing, and interesting, and I wish someone had said the XML files worked like nativelib packages. I'm guessing just about anything can go into a nativelib and the code will find it.
Java VM Arguments
Again, this should be pretty obvious, but it wasn't in the examples I saw on the web. If you have a java command line like this:
java -Xmx512m -DuseMyLog=true -DlogPath=logs/server.log -name Archie -type server
then the right way to split those up in the jnlp file is to put the -D arguments into the resources section and the regular args into the application-desc section. Something like this:
<resources>
<nativelib href="lib/cfg.jar" />
<j2se version="1.5.0+" href="http://java.sun.com/products/autodl/j2se"
max-heap-size="512m" />
<property name="useMyLog" value="true" />
<property name="logPath" value="logs/server.log" />
</resources>
<application-desc main-class="com.fun.MyServer">
<argument>-name</argument>
<argument>Archie</argument>
<argument>-type</argument>
<argument>server</argument>
</application-desc>
I spent a ton of time trying to figure out what went where and for what reason. They certainly could have done a lot more in terms of the examples and explanations for this stuff. But, that's what I'm doing now, isn't it?
Finishing Touches
Once I got the thing working, I needed to get it updating and such. An addition in the 1.6.0 JWS you can add the update tag and that will let JWS know how to update the app based on changes on the server-side. I really liked this as I needed to make sure that I had this capability, and sure enough, it was there, just like I needed.
<update check="always" policy="always" />
I have to admit that this has come a long way, and having it installed as a part of the JDK is really an important step in the right direction. I should be able to replace the third-party publish/subscribe application deployment system that's going away later this year with Java WebStart without too much trouble.
There are still things that I wish were there - variables. Make it so that you can put Java System property variables in the tags and then on invocation, have the JWS expand these. For example, say you wanted to put in the user name as an argument to the app. Since this is a static jnlp page served off an Apache web server, it's going to be very hard to get the username without placing a Java applet on the page that gets this data and sends it back to you in some form. Much too messy. Do this:
<application-desc main-class="com.fun.MyServer">
<argument>-name</argument>
<argument>Archie</argument>
<argument>-user</argument>
<argument>@user.name</argument>
</application-desc>
where the variable 'tag' @ is used to indicate that a Java System property variable name is following: user.name. Then, the JWS would replace the user's name in for this tag and pass the result to the application. This would solve a ton of issues as there are variables for most things you'd need, and the JWS is already running on the client machine, so it knows these things. It'd be really nice to have.
Thankfully, you can work that into your own code and do the same thing, but it's code we all don't need to write.