Problems integrating a cross platform Java desktop application

Having been involved in deploying a Java desktop application across a couple of the platforms supported by Java, I discovered various fairly serious problems which prevented easy integration of the application across these systems. I want to outline these issues and hopefully hear about some of the problems and solutions that others have faced.

1) Accurately locating standard directories and shell folders

Problem: The user.home property cannot be trusted on Windows because Windows does not have a cannonical “home directory” instead it creates a profile based on various shell folders, such as Personal which points usually points to My Documents, AppData which usually points to "C:\Documents and Settings\Application Data".

In all recent versions of Java the user.home property is discovered on Windows by looking up the current user’s Desktop directory from the registry and taking the parent folder of the desktop as the user’s home. This works fine on non-networked Windows installations which still use "C:\Document and Settings\" for all user shell folders. However on networks with roaming profiles these Shell folders can be redirected anywhere. On tightly controlled networks such as those in schools the user may not even have write access to all of these folders.

My employer has a product which is sold into schools. We almost immediately had a problem with this. All pupils at one school had their Desktop shell folder pointing to the same read-only network location. The users didn’t even have read access to the parent of this folder, and it definitely was not their ‘home’.

We needed to the find the home directory in order to build a path to the user’s Application Data settings directory, this was impossible on these systems. In order to work around this we had no choice but to turn to native code in order to access the registry and discover the real location of the AppData shell folder. In fact this situation is very common in schools as network administrators tend to lock down anything which pupils do not absolutely have to have write access to.

Solution: design a proper cross platform Java desktop integration API.

2) Storing preferences

Java provides an abstracted API for storing preferences. On Unix like platforms it uses hidden dot '.' directories under the user’s home folder to persist preference values. On Windows it uses the registry location \Software\JavaSoft\prefs under the current user‘s key and also under local machine.

Problem: As long as these preferences only need to be accessed by Java this works fine, however, as soon as someone needs to be able to customise a Java desktop application’s behaviour across a network the preferences API doesn’t help you.

The problem we faced here was that Java uses a very strange encoding for all paths it stores in these keys. For example if you set a preference to store a Windows file path in the registry it will look something like this:

"C:\\Documents\ and\ Settings\\myuser\\Application\ Data"

As far as I can tell the encoding is to add a backslash before every whitespace character and every backslash. Also the key names are illegible for similar reasons.

On a network which has it’s own network management tools admins can easily set registry keys which are visible over their entire network (e.g. with Windows Group Policy and Active Directory). It would be ridiculous to try to write a Java application to do this for them, and naive to presume that this Application would actually work and be useful across all the various network management platforms in use by schools today.

Also storing preferences here does not entirely follow the Windows way of doing things. Each piece of software is supposed to store it’s settings under \Software\.

The only way around this currently is to include JNI and native code to access the registry on Windows.

Solution: let Java programmers have access to platform specific features if they need it. Provide an abstracted API for the most common scenarios but Java should allow us to get to the guts of things if that’s what’s required.

3) Starting up a Java application

On each platform the application provider is left to provide their own method for building the classpath and running the application.

Sure Jar files are supposed to be executable and you can add classpath settings to the META-INF/MANIFEST.MF file. But not all platforms make Jar files executable certainly on Linux this isn’t the case unless you get an integrated JRE package from your vendor. Jar files do not let you provide an pretty icon for the executable. Often Jar files are identified with the wrong MIME type as really they are just ZIP files not executables, on Linux this is the case - currently Ubuntu assigns Jar files with the compressed file icon and opens them by default in an Archive tool. There are loads of other issues including problem with version conflicts see JSR 277 - Java Module System. It doesn’t allow you to specify a particular Java version to run it in.

On Unix systems you can write a shell script so that you can build the environment for your application. On Windows you end up needing a launcher tool like Launch4j because DOS is too limited as a shell scripting language. Sure tools like Ant and Tomcat use DOS scripts for bootstrapping but they are complex. We don’t all want to waste our time becoming DOS shell experts when there are better technologies to learn, and software to ship.

I can’t help being impressed by .Net’s use of a proper binary executable format. Although it uses the Windows Portable Executable format which isn’t native to Unix platforms, this isn’t a big problem as it’s easy to setup new executable formats in Linux using the binfmt facility in the kernel. This means that Mono (on Unix) can be assigned as the interpreter for .exe PE files on Unix and all works very well. The other thing I like about the .Net solution is the default config files which are paired with an EXE. These files sit in the directory with their exe and provide information on bootstrapping and linking the exe to assemblies. This is so useful - it takes the large majority of the work for setting up the application environment out of the bootstrapping scripts into a cross-platform configuration file. I wish Java had that. In fact at the recent Debconf7 in Edinburgh a suggestion was made to Tom Marble (the OpenJDK Ambassador) that the java command really needs to be able to read from a configuration file to reduce the often huge length of command line options passed to the Java command.

I have come to the conclusion that Java’s strict resistance to including any platform-specific capabilities (such as free registry access on Windows) prevents true cross platform integration of a Java application without resorting to JNI and native code. Also little cross platform help is provided to start up an application and build it’s classpath.