When developing Java, 99% of all tasks can be solved in a platform independent manor right out of the box. But then there is that last tiny bit of tasks, that is inherently platform specific, as it has to deal with the weirdness of the host-OS.
For the Pentaho Report-Designer, we support the three major desktop platforms – Linux, Windows and Mac OS. When ever we generate a document (be it when we preview the report or when we do a actual report-run), we have to show the user the newly generated document. The cheesy way of doing this is to assume a reasonable set of default applications. For PDF, we would for instance default to launching the “Acrobat Reader”. “Hey, I dont use closed-source applications from monopolistic vendors on my machine!” you may scream out in terror. And yes, assuming a set of “standard” applications when there is no standard is not a good thing.
Luckily, there is hope. Each operating system has a magic way of launching the “right” application for a given document. Of course, its not documented at all. So calling on numerous years of messing around with operating systems, here’s my cook-book for opening documents.
1. Linux (and also Solaris)
On most modern distributions, the mapping between mime-types and corresponding applications happens based on the rules expressed in a file called /etc/mailcap(5). The command-line utility run-mailcap(8) reads the mailcap file and automatically launches the right application for the given file. So running the default application is easy:
run-mailcap
or in Java:
Runtime.getRuntime().exec(new String[]{"run-mailcap", pathToYourFileAsString });
2. Windows
On Windows, file associations are stored in the registry. The registry is a binary file, so parsing that one is no fun. Of course, its also available via native C functions, but shipping platform dependent libraries is so 1995! Luckily, Microsoft drives a course of “never delete a documented function” and thus, the old tricks from Windows 95 still work on all recent Windows versions. Back in the old days, the most powerful toy to mess around with a system was the “rundll32” utility. This utility can be used to invoke functions from a library (dll-file), without having to write a C-programm (I’d rather read out Perl-regular expressions in the public than to go back to C again).
The Shell32.dll contains a nice function to run the default application called “ShellExec_RunDLL”. So let’s abuse that.
rundll32.exe "SHELL32.DLL,ShellExec_RunDLL"
3. Mac OSX
MacOS is a weird thing. Applications are stored in bundles, well, directories with a lot of binary gibberish to know what entry in there is executable. Its equally inaccessible as the Windows Registry and the Apple Developer Connection is a great place to never find anything (who would have guessed that the entry called “CFBundle” describes the application directory structure). The File-open dialog of course, treats these application bundles as if they where files, but sadly no one told the Unix-shell that these things are executable.
So we have to find magic again, this time by using the open(1) command to parse whatever makes a bundle so special and then to execute the correct native application inside the bundle.
If you just want to open the file with the default application, use
open
If you know the application bundle and want to open the file with that specific application, you cant do that directly. Again you have to use the open(1) command, but this time with a extra parameter:
open -a