Question

I'm using Java 1.5 and I'd like to launch the associated application to open the file. I know that Java 1.6 introduced the Desktop API, but I need a solution for Java 1.5.

So far I found a way to do it in Windows:

Runtime.getRuntime().exec(new String[]{ "rundll32", 
                          "url.dll,FileProtocolHandler", fileName });

Is there a cross-platform way to do it? Or at least a similar solution for Linux?

Was it helpful?

Solution

+1 for this answer

Additionally I would suggest the following implementation using polymorphism:

This way you can add new platform easier by reducing coupling among classes.

The Client code:

 Desktop desktop = Desktop.getDesktop();

 desktop.open( aFile );
 desktop.imaginaryAction( aFile );

The Desktop impl:

package your.pack.name;

import java.io.File;

public class Desktop{

    // hide the constructor.
    Desktop(){}

    // Created the appropriate instance
    public static Desktop getDesktop(){

        String os = System.getProperty("os.name").toLowerCase();

        Desktop desktop = new Desktop();
         // This uf/elseif/else code is used only once: here
        if ( os.indexOf("windows") != -1 || os.indexOf("nt") != -1){

            desktop = new WindowsDesktop();

        } else if ( os.equals("windows 95") || os.equals("windows 98") ){

            desktop = new Windows9xDesktop();

        } else if ( os.indexOf("mac") != -1 ) {

            desktop = new OSXDesktop();

        } else if ( os.indexOf("linux") != -1 && isGnome() ) {

            desktop = new GnomeDesktop();

        } else if ( os.indexOf("linux") != -1 && isKde() ) {

            desktop = new KdeDesktop();

        } else {
            throw new UnsupportedOperationException(String.format("The platform %s is not supported ",os) );
        }
        return desktop;
    }

    // default implementation :( 
    public void open( File file ){
        throw new UnsupportedOperationException();
    }

    // default implementation :( 
    public void imaginaryAction( File file  ){
        throw new UnsupportedOperationException();
    }
}

// One subclass per platform below:
// Each one knows how to handle its own platform   


class GnomeDesktop extends Desktop{

    public void open( File file ){
        // Runtime.getRuntime().exec: execute gnome-open <file>
    }

    public void imaginaryAction( File file ){
        // Runtime.getRuntime().exec:gnome-something-else <file>
    }

}
class KdeDesktop extends Desktop{

    public void open( File file ){
        // Runtime.getRuntime().exec: kfmclient exec <file>
    }

    public void imaginaryAction( File file ){
        // Runtime.getRuntime().exec: kfm-imaginary.sh  <file>
    }
}
class OSXDesktop extends Desktop{

    public void open( File file ){
        // Runtime.getRuntime().exec: open <file>
    }

    public void imaginaryAction( File file ){
        // Runtime.getRuntime().exec: wow!! <file>
    }
}
class WindowsDesktop extends Desktop{

    public void open( File file ){
        // Runtime.getRuntime().exec: cmd /c start <file>
    }

    public void imaginaryAction( File file ){
        // Runtime.getRuntime().exec: ipconfig /relese /c/d/e
    }
}
class Windows9xDesktop extends Desktop{

    public void open( File file ){
        //Runtime.getRuntime().exec: command.com /C start <file>
    }

    public void imaginaryAction( File file){
       //Runtime.getRuntime().exec: command.com /C otherCommandHere <file>
    }
}

This is only an example, in real life is not worth to create a new class only to parametrize a value ( the command string %s ) But let's do imagine that each method performs another steps in platform specific way.

Doing this kind of approach, may remove unneeded if/elseif/else constructs that with time may introduce bugs ( if there are 6 of these in the code and a change is neede, you may forget to update one of them, or by copy/pasting you may forget to change the command to execute)

OTHER TIPS

public static boolean isWindows() {
    String os = System.getProperty("os.name").toLowerCase();
    return os.indexOf("windows") != -1 || os.indexOf("nt") != -1;
}
public static boolean isMac() {
    String os = System.getProperty("os.name").toLowerCase();
    return os.indexOf("mac") != -1;
}
public static boolean isLinux() {
    String os = System.getProperty("os.name").toLowerCase();
    return os.indexOf("linux") != -1;
}
public static boolean isWindows9X() {
    String os = System.getProperty("os.name").toLowerCase();
    return os.equals("windows 95") || os.equals("windows 98");
}

and

 if (isLinux())
  {
     cmds.add(String.format("gnome-open %s", fileName));
     String subCmd = (exec) ? "exec" : "openURL";
     cmds.add(String.format("kfmclient "+subCmd+" %s", fileName));
  }
  else if (isMac())
  {
     cmds.add(String.format("open %s", fileName));
  }
  else if (isWindows() && isWindows9X())
  {
     cmds.add(String.format("command.com /C start %s", fileName));
  }
  else if (isWindows())
  {
     cmds.add(String.format("cmd /c start %s", fileName));
  }

JDIC is a library that provides Desktop-like functionality in Java 1.5.

Just as an addition: Rather than gnome-open, use xdg-open. It's part of the XdgUtils, which are in turn part of the LSB Desktop support package (starting with 3.2).

You can (should) still use gnome-open as a fallback, but xdg-open will also work on non-GNOME desktops.

SWT gives you the possibility to lokk for the standard program to open a file via:

final Program p = Program.findProgram(fileExtension);
p.execute(file.getAbsolutePath());

Strictly this isn't Cross-Platform since SWT is platform dependent, but for every platform you can use a diffenrent SWT jar.

You can use the OS default way to open it for you.

  • Windows: "cmd /c fileName
  • Linux w/gnome "gnome-open filename"
  • Linux w/Kde ??
  • OSx "open filename"

Another answer (by boutta) suggests using SWT. I wouldn't recommend referencing the library for this purpose only, but if you are using it already, simply execute:

Program.launch("http://google.com/");

Take note that this method will only work (and return true) if a Display object has already been created (for instance by creating a Shell). Also take note that it must run in the main thread; e.g.:

Display.syncExec(new Runnable() {
    public void run() {
        Program.launch("http://google.com/");
    }
});

In the example above I've launched a URL, but launching files works in the same way.

We do put the command outside somewhere in the configuration file.

Your "JAR and source code" will be "cross-platform", but your deployment doesn't.

You can also do something like this answer. You can put the classname of the factory class of the "Deskop" implementation into the setup file. (may be guide or spring, if you like)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top