views:

177

answers:

6

I would like to implement a java application (server application) that can download a new version (.jar file) from a given url, and then update itself at runtime.

What is the best way to do this and is it possible?

I guess that the application can download a new .jar file and start it. But how should I do the handover, e.g. know when the new application is started and then exit. Or is there a better way to do this?

+1  A: 

This isn't necessarily the best way, but it might work for you.

You can write a bootstrap application (ala the World of Warcraft launcher, if you've played WoW). That bootstrap is responsible for checking for updates.

  • If an update is available, it will offer it to the user, handle the download, installation, etc.
  • If the application is up to date, it will allow the user to launch the application
  • Optionally, you can allow the user to launch the application, even if it isn't up to date

This way you don't have to worry about forcing an exit of your application.

If your application is web based, and if it is important that they have an up to date client, then you can also do version checks while the application runs. You can do them at intervals, while performing normal communication with the server (some or all calls), or both.

For a product I recently worked on, we did version checks upon launch (without a boot strapper app, but before the main window appeared), and during calls to the server. When the client was out of date, we relied on the user to quit manually, but forbid any action against the server.

Please note that I don't know if Java can invoke UI code before you bring up your main window. We were using C#/WPF.

Merlyn Morgan-Graham
Thanks, that is a nice way to do it. But it's a server application so there is no user that can take some action. And I would prefer that it's only a single jar file, so the user easyli can download a single jar and start it at the beginning, but after that I would like to have no user interactions.
Jonas
When you say "server application", do you mean that it is an application that is run directly on the server, while logged in?
Merlyn Morgan-Graham
@Jonas: I don't understand much about how .jar files work, so I can't be of much service there. I can understand if you would prefer an answer specific to Java. Hopefully this gives you food for thought, at least :)
Merlyn Morgan-Graham
@Merlyn: I am thankful for sharing your ideas. Yes, it's a Java application that will be running on a Linux server, and no one is logged in on that server.
Jonas
@Jonas: How will it execute? Via cron? (not to say that fact would change anything, just curious). Do you need to do an update while in the middle of running the app, or can you live with it being updated when the auto-run cycle comes around?
Merlyn Morgan-Graham
@Merlyn: No, I think it will be running 24/7 as a web server do, in example.
Jonas
@Jonas: Not that you hadn't already thought about this, but - Most web services I've seen have a manual deployment strategy. You may want to be careful about how you check for updates. If you push up buggy/broken code, or only get part way done w/ a multi-file deploy, the server might try to update itself, and then you'd have a broken server.
Merlyn Morgan-Graham
@Merlyn: That's true, and the security is also important. It's only a small monitoring application that will be used internally on a few servers.
Jonas
+7  A: 

I've written a java application that can load plugins at runtime and start using them immediately, inspired by a similar mechanism in jEdit. jEdit is open source so you have to option of looking to see how it does things.

The solution uses a custom ClassLoader to load files from the jar. Once they're loaded you can invoke some method from the new jar that will act as it's main method. Then the tricky part is making sure you get rid of all references to the old code so that it can be garbage collected. I'm not quite an expert on that part, I've made it work but it wasn't easy.

bemace
I don't know about Java, but in C#, you can use AppDomains to explicitly unload code. Maybe there is a similar concept in Java.
Merlyn Morgan-Graham
+1. Good suggestion
Merlyn Morgan-Graham
Thanks, this seems to be the way to go. There is an example of a `NetworkClassLoader` on the JavaDoc for [ClassLoader](http://download.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html)
Jonas
Did you run into problems with static variables within the same JVM, or what about the permanent generation? I have heard these can present issues in regard to class unloading.
ide
+2  A: 

The basic structure of a solution is as follows:

  • There is a main loop responsible for repeatedly loading the latest version of the app (if required) and launching it.

  • The application does its thing, but periodically checks the download URL. If it detects a new version it exits back to the launcher.

There are a number of ways you could implement this. For example:

  • The launcher could be a wrapper script or binary application that starts a new JVM to run the application from a JAR file that gets replaced.

  • The launcher could be a Java application that creates a classloader for the new JAR, loads an entrypoint class and calls some method on it. If you do it this way, you have to watch for classloader storage leaks, but that's not difficult. (You just need to make sure that no objects with classes loaded from the JAR are reachable after you relaunch.)

The advantages of the external wrapper approach are:

  • you only need one JAR,
  • you can replace the entire Java app,
  • any secondary threads created by the app, etc will go away without special shutdown logic, and
  • you can also deal with recovery from application crashes, etc.

The second approach requires two JARs, but has the following advantages:

  • the solution is pure Java and portable,
  • the changeover will be quicker, and
  • you can more easily retain state across the restart (modulo leakage issues).

The "best" way depends on your specific requirements.

Stephen C
+1  A: 
  1. First way: use tomcat and it's deploy facilities.
  2. Second way: to split application on two parts (functional and update) and let update part replace function part.
  3. Third way: In your server appliction just download new version, then old version releases bound port, then old version runs new version (starts process), then old version sends a request on application port to the new version to delete old version, old version terminates and new version deletes old version. Like this: alt text
ycnix
Your second way seems to be an interesting design.
Jonas
+1  A: 

If you build your application using Equinox plugins, you can use the P2 Provisioning System to get a ready-made solution to this problem. This will require the server to restart itself after an update.

pelotom
+1  A: 

This is a known problem and I recommend against reinventing a wheel - don't write your own hack, just use what other people have already done.

Two situations you need to consider:

  1. App needs to be self-updatable and keep running even during update (server app, embedded apps). Go with OSGi: Bundles or Equinox p2.

  2. App is a desktop app and has an installer. There are many installers with update option. Check installers list.

Peter Knego