views:

2755

answers:

7

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?

+3  A: 

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.

boutta
Note: the source of Program.java are here http://kickjava.com/src/org/eclipse/swt/program/Program.java.htm . May be that can help too
VonC
Probably this is very useful for Java 1.5 + SWT users. But using SWT for only this might not be optimal.
asalamon74
A: 

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"
OscarRyz
+7  A: 
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));
  }
Willi aus Rohr
You may also, take polymorphism with that. That way you can add flexibility to the implementation. Then you can avoid another if/elseif/else chain for the next operation.
OscarRyz
You should use `xdg-open` instead of `gnome-open` or `kfmclient` or whatever, so it works more nicely in xfce or other environments.
jleedev
+7  A: 

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

Dan Vinton
This library seems to solve the problem. I don't understand why people voted up for reinventing the wheel...
Lucas -luky- N.
+7  A: 

+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)

OscarRyz
A: 

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)

Dennis Cheung
+4  A: 

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.

Torsten Marek
Great addition. I was not aware of this package.
asalamon74