Tuesday, April 21, 2009

Java Application and self-restart

Java's networking capabilities and prebuilt classes make self-updating applications an easy task for developers. A simple method is to store a file containing current version number on a web host, together with a zipped/tared file containing the whole or partial application files to update.

Also, java applications are truly self-updatable since the application itself can overwrite its class files (or jar ones), since the java VM loads all its contents into memory before start up (except for dynamic 'late' class loading).

After coding the necessary classes to perform the update I realised I needed a way to tell java to restart the application, loading the updated code from the new class files. There wasn't an automated way to do this, so I came up with the next piece of code which invokes the java VM to execute the JAR file where certain class belongs to.



public boolean restartApplication( Object classInJarFile )
{
String javaBin = System.getProperty("java.home") + "/bin/java";
File jarFile;
try{
jarFile = new File
(classInJarFile.getClass().getProtectionDomain()
.getCodeSource().getLocation().toURI());
} catch(Exception e) {
return false;
}

/* is it a jar file? */
if ( !jarFile.getName().endsWith(".jar") )
return false; //no, it's a .class probably

String toExec[] = new String[] { javaBin, "-jar", jarFile.getPath() };
try{
Process p = Runtime.getRuntime().exec( toExec );
} catch(Exception e) {
e.printStackTrace();
return false;
}

System.exit(0);

return true;
}

There are some important aspects to have in mind for this code:

  • The application's main class must be in a jar file. classInJarFile must be an instance of any class inside the same jar file (could be the main class too).
  • The called java VM will be the same that the application is currently running on.
  • There is no special error checking: the java VM may return an error like class not found or jar not found, and it will not be caught by the code posted above.
  • The function will never return if it doesn't catch an error. It would be a good practice to close all the handlers that could conflict with the 'duplicate' new application before calling restartApplication(). There will be a small time (which depends on many factors) where both applications will be running at the same time.

The code can be easily modified for a class file approach rather than jar ones.

A bash script or .bat (Windows) would work, calling the application indefinitely in the case the process' return value matches a specified number (which would be set after a successful upgrade). However, this wouldn't be platform independent.

5 comments:

  1. Thanks for the code. It is very useful. I am going to use in in JStock.

    ReplyDelete
  2. Thanks a bunch for this.

    ReplyDelete
  3. Thanks for the method, excellent work, How do you use the Method ..

    ReplyDelete
  4. Just call the method with classInJarFile being an instance of any class inside the same jar file in which your app is contained, as said above. This is necessary so the method knows the jar file to run with the JVM.

    ReplyDelete
  5. Demo code

    https://github.com/cird/RestartApplicationDemo

    ReplyDelete