Clover coverage report - baseCode - 0.2.5
Coverage timestamp: Tue Apr 12 2005 11:31:58 EDT
file stats: LOC: 673   Methods: 4
NCLOC: 464   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
BrowserLauncher.java 0% 0% 0% 0%
coverage
 1   
 // package edu.stanford.ejalbert;
 2   
 package baseCode.util;
 3   
 
 4   
 import java.io.File;
 5   
 import java.io.IOException;
 6   
 import java.lang.reflect.Constructor;
 7   
 import java.lang.reflect.Field;
 8   
 import java.lang.reflect.InvocationTargetException;
 9   
 import java.lang.reflect.Method;
 10   
 
 11   
 /**
 12   
  * BrowserLauncher is a class that provides one static method, openURL, which opens the default web browser for the
 13   
  * current user of the system to the given URL. It may support other protocols depending on the system -- mailto, ftp,
 14   
  * etc. -- but that has not been rigorously tested and is not guaranteed to work.
 15   
  * <p>
 16   
  * Yes, this is platform-specific code, and yes, it may rely on classes on certain platforms that are not part of the
 17   
  * standard JDK. What we're trying to do, though, is to take something that's frequently desirable but inherently
 18   
  * platform-specific -- opening a default browser -- and allow programmers (you, for example) to do so without worrying
 19   
  * about dropping into native code or doing anything else similarly evil.
 20   
  * <p>
 21   
  * Anyway, this code is completely in Java and will run on all JDK 1.1-compliant systems without modification or a need
 22   
  * for additional libraries. All classes that are required on certain platforms to allow this to run are dynamically
 23   
  * loaded at runtime via reflection and, if not found, will not cause this to do anything other than returning an error
 24   
  * when opening the browser.
 25   
  * <p>
 26   
  * There are certain system requirements for this class, as it's running through Runtime.exec(), which is Java's way of
 27   
  * making a native system call. Currently, this requires that a Macintosh have a Finder which supports the GURL event,
 28   
  * which is true for Mac OS 8.0 and 8.1 systems that have the Internet Scripting AppleScript dictionary installed in the
 29   
  * Scripting Additions folder in the Extensions folder (which is installed by default as far as I know under Mac OS 8.0
 30   
  * and 8.1), and for all Mac OS 8.5 and later systems. On Windows, it only runs under Win32 systems (Windows 95, 98, and
 31   
  * NT 4.0, as well as later versions of all). On other systems, this drops back from the inherently platform-sensitive
 32   
  * concept of a default browser and simply attempts to launch Netscape via a shell command.
 33   
  * <p>
 34   
  * This code is Copyright 1999-2001 by Eric Albert (ejalbert@cs.stanford.edu) and may be redistributed or modified in
 35   
  * any form without restrictions as long as the portion of this comment from this paragraph through the end of the
 36   
  * comment is not removed. The author requests that he be notified of any application, applet, or other binary that
 37   
  * makes use of this code, but that's more out of curiosity than anything and is not required. This software includes no
 38   
  * warranty. The author is not repsonsible for any loss of data or functionality or any adverse or unexpected effects of
 39   
  * using this software.
 40   
  * <p>
 41   
  * Credits: <br>
 42   
  * Steven Spencer, JavaWorld magazine ( <a href="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java Tip
 43   
  * 66 </a>) <br>
 44   
  * Thanks also to Ron B. Yeh, Eric Shapiro, Ben Engber, Paul Teitlebaum, Andrea Cantatore, Larry Barowski, Trevor
 45   
  * Bedzek, Frank Miedrich, and Ron Rabakukk
 46   
  * 
 47   
  * @author Eric Albert ( <a href="mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu </a>)
 48   
  * @version 1.4b1 (Released June 20, 2001)
 49   
  */
 50   
 public class BrowserLauncher {
 51   
 
 52   
    /**
 53   
     * The Java virtual machine that we are running on. Actually, in most cases we only care about the operating system,
 54   
     * but some operating systems require us to switch on the VM.
 55   
     */
 56   
    private static int jvm;
 57   
 
 58   
    /** The browser for the system */
 59   
    private static Object browser;
 60   
 
 61   
    /**
 62   
     * Caches whether any classes, methods, and fields that are not part of the JDK and need to be dynamically loaded at
 63   
     * runtime loaded successfully.
 64   
     * <p>
 65   
     * Note that if this is <code>false</code>,<code>openURL()</code> will always return an IOException.
 66   
     */
 67   
    private static boolean loadedWithoutErrors;
 68   
 
 69   
    /** The com.apple.mrj.MRJFileUtils class */
 70   
    private static Class mrjFileUtilsClass;
 71   
 
 72   
    /** The com.apple.mrj.MRJOSType class */
 73   
    private static Class mrjOSTypeClass;
 74   
 
 75   
    /** The com.apple.MacOS.AEDesc class */
 76   
    private static Class aeDescClass;
 77   
 
 78   
    /** The <init>(int) method of com.apple.MacOS.AETarget */
 79   
    private static Constructor aeTargetConstructor;
 80   
 
 81   
    /** The <init>(int, int, int) method of com.apple.MacOS.AppleEvent */
 82   
    private static Constructor appleEventConstructor;
 83   
 
 84   
    /** The <init>(String) method of com.apple.MacOS.AEDesc */
 85   
    private static Constructor aeDescConstructor;
 86   
 
 87   
    /** The findFolder method of com.apple.mrj.MRJFileUtils */
 88   
    private static Method findFolder;
 89   
 
 90   
    /** The getFileCreator method of com.apple.mrj.MRJFileUtils */
 91   
    private static Method getFileCreator;
 92   
 
 93   
    /** The getFileType method of com.apple.mrj.MRJFileUtils */
 94   
    private static Method getFileType;
 95   
 
 96   
    /** The openURL method of com.apple.mrj.MRJFileUtils */
 97   
    private static Method openURL;
 98   
 
 99   
    /** The makeOSType method of com.apple.MacOS.OSUtils */
 100   
    private static Method makeOSType;
 101   
 
 102   
    /** The putParameter method of com.apple.MacOS.AppleEvent */
 103   
    private static Method putParameter;
 104   
 
 105   
    /** The sendNoReply method of com.apple.MacOS.AppleEvent */
 106   
    private static Method sendNoReply;
 107   
 
 108   
    /** Actually an MRJOSType pointing to the System Folder on a Macintosh */
 109   
    private static Object kSystemFolderType;
 110   
 
 111   
    /** The keyDirectObject AppleEvent parameter type */
 112   
    private static Integer keyDirectObject;
 113   
 
 114   
    /** The kAutoGenerateReturnID AppleEvent code */
 115   
    private static Integer kAutoGenerateReturnID;
 116   
 
 117   
    /** The kAnyTransactionID AppleEvent code */
 118   
    private static Integer kAnyTransactionID;
 119   
 
 120   
    /** The linkage object required for JDirect 3 on Mac OS X. */
 121   
    private static Object linkage;
 122   
 
 123   
    /** The framework to reference on Mac OS X */
 124   
    private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
 125   
 
 126   
    /** JVM constant for MRJ 2.0 */
 127   
    private static final int MRJ_2_0 = 0;
 128   
 
 129   
    /** JVM constant for MRJ 2.1 or later */
 130   
    private static final int MRJ_2_1 = 1;
 131   
 
 132   
    /** JVM constant for Java on Mac OS X 10.0 (MRJ 3.0) */
 133   
    private static final int MRJ_3_0 = 3;
 134   
 
 135   
    /** JVM constant for MRJ 3.1 */
 136   
    private static final int MRJ_3_1 = 4;
 137   
 
 138   
    /** JVM constant for any Windows NT JVM */
 139   
    private static final int WINDOWS_NT = 5;
 140   
 
 141   
    /** JVM constant for any Windows 9x JVM */
 142   
    private static final int WINDOWS_9x = 6;
 143   
 
 144   
    /** JVM constant for any other platform */
 145   
    private static final int OTHER = -1;
 146   
 
 147   
    /**
 148   
     * The file type of the Finder on a Macintosh. Hardcoding "Finder" would keep non-U.S. English systems from working
 149   
     * properly.
 150   
     */
 151   
    private static final String FINDER_TYPE = "FNDR";
 152   
 
 153   
    /**
 154   
     * The creator code of the Finder on a Macintosh, which is needed to send AppleEvents to the application.
 155   
     */
 156   
    private static final String FINDER_CREATOR = "MACS";
 157   
 
 158   
    /** The name for the AppleEvent type corresponding to a GetURL event. */
 159   
    private static final String GURL_EVENT = "GURL";
 160   
 
 161   
    /**
 162   
     * The first parameter that needs to be passed into Runtime.exec() to open the default web browser on Windows.
 163   
     */
 164   
    private static final String FIRST_WINDOWS_PARAMETER = "/c";
 165   
 
 166   
    /** The second parameter for Runtime.exec() on Windows. */
 167   
    private static final String SECOND_WINDOWS_PARAMETER = "start";
 168   
 
 169   
    /**
 170   
     * The third parameter for Runtime.exec() on Windows. This is a "title" parameter that the command line expects.
 171   
     * Setting this parameter allows URLs containing spaces to work.
 172   
     */
 173   
    private static final String THIRD_WINDOWS_PARAMETER = "\"\"";
 174   
 
 175   
    /**
 176   
     * The shell parameters for Netscape that opens a given URL in an already-open copy of Netscape on many command-line
 177   
     * systems.
 178   
     */
 179   
    private static final String NETSCAPE_REMOTE_PARAMETER = "-remote";
 180   
    private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
 181   
    private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
 182   
 
 183   
    /**
 184   
     * The message from any exception thrown throughout the initialization process.
 185   
     */
 186   
    private static String errorMessage;
 187   
 
 188   
    /**
 189   
     * An initialization block that determines the operating system and loads the necessary runtime data.
 190   
     */
 191   
    static {
 192  0
       loadedWithoutErrors = true;
 193  0
       String osName = System.getProperty( "os.name" );
 194  0
       if ( osName.startsWith( "Mac OS" ) ) {
 195  0
          String mrjVersion = System.getProperty( "mrj.version" );
 196  0
          String majorMRJVersion = mrjVersion.substring( 0, 3 );
 197  0
          try {
 198  0
             double version = Double.valueOf( majorMRJVersion ).doubleValue();
 199  0
             if ( version == 2 ) {
 200  0
                jvm = MRJ_2_0;
 201  0
             } else if ( version >= 2.1 && version < 3 ) {
 202   
                // Assume that all 2.x versions of MRJ work the same. MRJ 2.1 actually
 203   
                // works via Runtime.exec() and 2.2 supports that but has an openURL() method
 204   
                // as well that we currently ignore.
 205  0
                jvm = MRJ_2_1;
 206  0
             } else if ( version == 3.0 ) {
 207  0
                jvm = MRJ_3_0;
 208  0
             } else if ( version >= 3.1 ) {
 209   
                // Assume that all 3.1 and later versions of MRJ work the same.
 210  0
                jvm = MRJ_3_1;
 211   
             } else {
 212  0
                loadedWithoutErrors = false;
 213  0
                errorMessage = "Unsupported MRJ version: " + version;
 214   
             }
 215   
          } catch ( NumberFormatException nfe ) {
 216  0
             loadedWithoutErrors = false;
 217  0
             errorMessage = "Invalid MRJ version: " + mrjVersion;
 218   
          }
 219  0
       } else if ( osName.startsWith( "Windows" ) ) {
 220  0
          if ( osName.indexOf( "9" ) != -1 ) {
 221  0
             jvm = WINDOWS_9x;
 222   
          } else {
 223  0
             jvm = WINDOWS_NT;
 224   
          }
 225   
       } else {
 226  0
          jvm = OTHER;
 227   
       }
 228   
 
 229  0
       if ( loadedWithoutErrors ) { // if we haven't hit any errors yet
 230  0
          loadedWithoutErrors = loadClasses();
 231   
       }
 232   
    }
 233   
 
 234   
    /**
 235   
     * This class should be never be instantiated; this just ensures so.
 236   
     */
 237  0
    private BrowserLauncher() {
 238   
    }
 239   
 
 240   
    /**
 241   
     * Called by a static initializer to load any classes, fields, and methods required at runtime to locate the user's
 242   
     * web browser.
 243   
     * 
 244   
     * @return <code>true</code> if all intialization succeeded <code>false</code> if any portion of the
 245   
     *         initialization failed
 246   
     */
 247  0
    private static boolean loadClasses() {
 248  0
       switch ( jvm ) {
 249   
          case MRJ_2_0:
 250  0
             try {
 251  0
                Class aeTargetClass = Class.forName( "com.apple.MacOS.AETarget" );
 252  0
                Class osUtilsClass = Class.forName( "com.apple.MacOS.OSUtils" );
 253  0
                Class appleEventClass = Class
 254   
                      .forName( "com.apple.MacOS.AppleEvent" );
 255  0
                Class aeClass = Class.forName( "com.apple.MacOS.ae" );
 256  0
                aeDescClass = Class.forName( "com.apple.MacOS.AEDesc" );
 257   
 
 258  0
                aeTargetConstructor = aeTargetClass
 259   
                      .getDeclaredConstructor( new Class[] {
 260   
                         int.class
 261   
                      } );
 262  0
                appleEventConstructor = appleEventClass
 263   
                      .getDeclaredConstructor( new Class[] {
 264   
                            int.class, int.class, aeTargetClass, int.class,
 265   
                            int.class
 266   
                      } );
 267  0
                aeDescConstructor = aeDescClass
 268   
                      .getDeclaredConstructor( new Class[] {
 269   
                         String.class
 270   
                      } );
 271   
 
 272  0
                makeOSType = osUtilsClass.getDeclaredMethod( "makeOSType",
 273   
                      new Class[] {
 274   
                         String.class
 275   
                      } );
 276  0
                putParameter = appleEventClass.getDeclaredMethod(
 277   
                      "putParameter", new Class[] {
 278   
                            int.class, aeDescClass
 279   
                      } );
 280  0
                sendNoReply = appleEventClass.getDeclaredMethod( "sendNoReply",
 281   
                      new Class[] {} );
 282   
 
 283  0
                Field keyDirectObjectField = aeClass
 284   
                      .getDeclaredField( "keyDirectObject" );
 285  0
                keyDirectObject = ( Integer ) keyDirectObjectField.get( null );
 286  0
                Field autoGenerateReturnIDField = appleEventClass
 287   
                      .getDeclaredField( "kAutoGenerateReturnID" );
 288  0
                kAutoGenerateReturnID = ( Integer ) autoGenerateReturnIDField
 289   
                      .get( null );
 290  0
                Field anyTransactionIDField = appleEventClass
 291   
                      .getDeclaredField( "kAnyTransactionID" );
 292  0
                kAnyTransactionID = ( Integer ) anyTransactionIDField.get( null );
 293   
             } catch ( ClassNotFoundException cnfe ) {
 294  0
                errorMessage = cnfe.getMessage();
 295  0
                return false;
 296   
             } catch ( NoSuchMethodException nsme ) {
 297  0
                errorMessage = nsme.getMessage();
 298  0
                return false;
 299   
             } catch ( NoSuchFieldException nsfe ) {
 300  0
                errorMessage = nsfe.getMessage();
 301  0
                return false;
 302   
             } catch ( IllegalAccessException iae ) {
 303  0
                errorMessage = iae.getMessage();
 304  0
                return false;
 305   
             }
 306  0
             break;
 307   
          case MRJ_2_1:
 308  0
             try {
 309  0
                mrjFileUtilsClass = Class.forName( "com.apple.mrj.MRJFileUtils" );
 310  0
                mrjOSTypeClass = Class.forName( "com.apple.mrj.MRJOSType" );
 311  0
                Field systemFolderField = mrjFileUtilsClass
 312   
                      .getDeclaredField( "kSystemFolderType" );
 313  0
                kSystemFolderType = systemFolderField.get( null );
 314  0
                findFolder = mrjFileUtilsClass.getDeclaredMethod( "findFolder",
 315   
                      new Class[] {
 316   
                         mrjOSTypeClass
 317   
                      } );
 318  0
                getFileCreator = mrjFileUtilsClass.getDeclaredMethod(
 319   
                      "getFileCreator", new Class[] {
 320   
                         File.class
 321   
                      } );
 322  0
                getFileType = mrjFileUtilsClass.getDeclaredMethod(
 323   
                      "getFileType", new Class[] {
 324   
                         File.class
 325   
                      } );
 326   
             } catch ( ClassNotFoundException cnfe ) {
 327  0
                errorMessage = cnfe.getMessage();
 328  0
                return false;
 329   
             } catch ( NoSuchFieldException nsfe ) {
 330  0
                errorMessage = nsfe.getMessage();
 331  0
                return false;
 332   
             } catch ( NoSuchMethodException nsme ) {
 333  0
                errorMessage = nsme.getMessage();
 334  0
                return false;
 335   
             } catch ( SecurityException se ) {
 336  0
                errorMessage = se.getMessage();
 337  0
                return false;
 338   
             } catch ( IllegalAccessException iae ) {
 339  0
                errorMessage = iae.getMessage();
 340  0
                return false;
 341   
             }
 342  0
             break;
 343   
          case MRJ_3_0:
 344  0
             try {
 345  0
                Class linker = Class.forName( "com.apple.mrj.jdirect.Linker" );
 346  0
                Constructor constructor = linker.getConstructor( new Class[] {
 347   
                   Class.class
 348   
                } );
 349  0
                linkage = constructor.newInstance( new Object[] {
 350   
                   BrowserLauncher.class
 351   
                } );
 352   
             } catch ( ClassNotFoundException cnfe ) {
 353  0
                errorMessage = cnfe.getMessage();
 354  0
                return false;
 355   
             } catch ( NoSuchMethodException nsme ) {
 356  0
                errorMessage = nsme.getMessage();
 357  0
                return false;
 358   
             } catch ( InvocationTargetException ite ) {
 359  0
                errorMessage = ite.getMessage();
 360  0
                return false;
 361   
             } catch ( InstantiationException ie ) {
 362  0
                errorMessage = ie.getMessage();
 363  0
                return false;
 364   
             } catch ( IllegalAccessException iae ) {
 365  0
                errorMessage = iae.getMessage();
 366  0
                return false;
 367   
             }
 368  0
             break;
 369   
          case MRJ_3_1:
 370  0
             try {
 371  0
                mrjFileUtilsClass = Class.forName( "com.apple.mrj.MRJFileUtils" );
 372  0
                openURL = mrjFileUtilsClass.getDeclaredMethod( "openURL",
 373   
                      new Class[] {
 374   
                         String.class
 375   
                      } );
 376   
             } catch ( ClassNotFoundException cnfe ) {
 377  0
                errorMessage = cnfe.getMessage();
 378  0
                return false;
 379   
             } catch ( NoSuchMethodException nsme ) {
 380  0
                errorMessage = nsme.getMessage();
 381  0
                return false;
 382   
             }
 383  0
             break;
 384   
          default:
 385  0
             break;
 386   
       }
 387  0
       return true;
 388   
    }
 389   
 
 390   
    /**
 391   
     * Attempts to locate the default web browser on the local system. Caches results so it only locates the browser once
 392   
     * for each use of this class per JVM instance.
 393   
     * 
 394   
     * @return The browser for the system. Note that this may not be what you would consider to be a standard web
 395   
     *         browser; instead, it's the application that gets called to open the default web browser. In some cases,
 396   
     *         this will be a non-String object that provides the means of calling the default browser.
 397   
     */
 398  0
    private static Object locateBrowser() {
 399  0
       if ( browser != null ) {
 400  0
          return browser;
 401   
       }
 402  0
       switch ( jvm ) {
 403   
          case MRJ_2_0:
 404  0
             try {
 405  0
                Integer finderCreatorCode = ( Integer ) makeOSType.invoke( null,
 406   
                      new Object[] {
 407   
                         FINDER_CREATOR
 408   
                      } );
 409  0
                Object aeTarget = aeTargetConstructor.newInstance( new Object[] {
 410   
                   finderCreatorCode
 411   
                } );
 412  0
                Integer gurlType = ( Integer ) makeOSType.invoke( null,
 413   
                      new Object[] {
 414   
                         GURL_EVENT
 415   
                      } );
 416  0
                Object appleEvent = appleEventConstructor
 417   
                      .newInstance( new Object[] {
 418   
                            gurlType, gurlType, aeTarget, kAutoGenerateReturnID,
 419   
                            kAnyTransactionID
 420   
                      } );
 421   
                // Don't set browser = appleEvent because then the next time we call
 422   
                // locateBrowser(), we'll get the same AppleEvent, to which we'll already have
 423   
                // added the relevant parameter. Instead, regenerate the AppleEvent every time.
 424   
                // There's probably a way to do this better; if any has any ideas, please let
 425   
                // me know.
 426  0
                return appleEvent;
 427   
             } catch ( IllegalAccessException iae ) {
 428  0
                browser = null;
 429  0
                errorMessage = iae.getMessage();
 430  0
                return browser;
 431   
             } catch ( InstantiationException ie ) {
 432  0
                browser = null;
 433  0
                errorMessage = ie.getMessage();
 434  0
                return browser;
 435   
             } catch ( InvocationTargetException ite ) {
 436  0
                browser = null;
 437  0
                errorMessage = ite.getMessage();
 438  0
                return browser;
 439   
             }
 440   
          case MRJ_2_1:
 441  0
             File systemFolder;
 442  0
             try {
 443  0
                systemFolder = ( File ) findFolder.invoke( null, new Object[] {
 444   
                   kSystemFolderType
 445   
                } );
 446   
             } catch ( IllegalArgumentException iare ) {
 447  0
                browser = null;
 448  0
                errorMessage = iare.getMessage();
 449  0
                return browser;
 450   
             } catch ( IllegalAccessException iae ) {
 451  0
                browser = null;
 452  0
                errorMessage = iae.getMessage();
 453  0
                return browser;
 454   
             } catch ( InvocationTargetException ite ) {
 455  0
                browser = null;
 456  0
                errorMessage = ite.getTargetException().getClass() + ": "
 457   
                      + ite.getTargetException().getMessage();
 458  0
                return browser;
 459   
             }
 460  0
             String[] systemFolderFiles = systemFolder.list();
 461   
             // Avoid a FilenameFilter because that can't be stopped mid-list
 462  0
             for ( int i = 0; i < systemFolderFiles.length; i++ ) {
 463  0
                try {
 464  0
                   File file = new File( systemFolder, systemFolderFiles[i] );
 465  0
                   if ( !file.isFile() ) {
 466  0
                      continue;
 467   
                   }
 468   
                   // We're looking for a file with a creator code of 'MACS' and
 469   
                   // a type of 'FNDR'. Only requiring the type results in non-Finder
 470   
                   // applications being picked up on certain Mac OS 9 systems,
 471   
                   // especially German ones, and sending a GURL event to those
 472   
                   // applications results in a logout under Multiple Users.
 473  0
                   Object fileType = getFileType.invoke( null, new Object[] {
 474   
                      file
 475   
                   } );
 476  0
                   if ( FINDER_TYPE.equals( fileType.toString() ) ) {
 477  0
                      Object fileCreator = getFileCreator.invoke( null,
 478   
                            new Object[] {
 479   
                               file
 480   
                            } );
 481  0
                      if ( FINDER_CREATOR.equals( fileCreator.toString() ) ) {
 482  0
                         browser = file.toString(); // Actually the Finder, but that's OK
 483  0
                         return browser;
 484   
                      }
 485   
                   }
 486   
                } catch ( IllegalArgumentException iare ) {
 487   
                   //browser = browser;
 488  0
                   errorMessage = iare.getMessage();
 489  0
                   return null;
 490   
                } catch ( IllegalAccessException iae ) {
 491  0
                   browser = null;
 492  0
                   errorMessage = iae.getMessage();
 493  0
                   return browser;
 494   
                } catch ( InvocationTargetException ite ) {
 495  0
                   browser = null;
 496  0
                   errorMessage = ite.getTargetException().getClass() + ": "
 497   
                         + ite.getTargetException().getMessage();
 498  0
                   return browser;
 499   
                }
 500   
             }
 501  0
             browser = null;
 502  0
             break;
 503   
          case MRJ_3_0:
 504   
          case MRJ_3_1:
 505  0
             browser = ""; // Return something non-null
 506  0
             break;
 507   
          case WINDOWS_NT:
 508  0
             browser = "cmd.exe";
 509  0
             break;
 510   
          case WINDOWS_9x:
 511  0
             browser = "command.com";
 512  0
             break;
 513   
          case OTHER:
 514   
          default:
 515  0
             browser = "netscape";
 516  0
             break;
 517   
       }
 518  0
       return browser;
 519   
    }
 520   
 
 521   
    /**
 522   
     * Attempts to open the default web browser to the given URL.
 523   
     * 
 524   
     * @param url The URL to open
 525   
     * @throws IOException If the web browser could not be located or does not run
 526   
     */
 527  0
    public static void openURL( String url ) throws IOException {
 528  0
       if ( !loadedWithoutErrors ) {
 529  0
          throw new IOException( "Exception in finding browser: " + errorMessage );
 530   
       }
 531  0
       Object browser = locateBrowser();
 532  0
       if ( browser == null ) {
 533  0
          throw new IOException( "Unable to locate browser: " + errorMessage );
 534   
       }
 535   
 
 536  0
       switch ( jvm ) {
 537   
          case MRJ_2_0:
 538  0
             Object aeDesc = null;
 539  0
             try {
 540  0
                aeDesc = aeDescConstructor.newInstance( new Object[] {
 541   
                   url
 542   
                } );
 543  0
                putParameter.invoke( browser, new Object[] {
 544   
                      keyDirectObject, aeDesc
 545   
                } );
 546  0
                sendNoReply.invoke( browser, new Object[] {} );
 547   
             } catch ( InvocationTargetException ite ) {
 548  0
                throw new IOException(
 549   
                      "InvocationTargetException while creating AEDesc: "
 550   
                            + ite.getMessage() );
 551   
             } catch ( IllegalAccessException iae ) {
 552  0
                throw new IOException(
 553   
                      "IllegalAccessException while building AppleEvent: "
 554   
                            + iae.getMessage() );
 555   
             } catch ( InstantiationException ie ) {
 556  0
                throw new IOException(
 557   
                      "InstantiationException while creating AEDesc: "
 558   
                            + ie.getMessage() );
 559   
             } finally {
 560  0
                aeDesc = null; // Encourage it to get disposed if it was created
 561  0
                browser = null; // Ditto
 562   
             }
 563  0
             break;
 564   
          case MRJ_2_1:
 565  0
             Runtime.getRuntime().exec( new String[] {
 566   
                   ( String ) browser, url
 567   
             } );
 568  0
             break;
 569   
          case MRJ_3_0:
 570  0
             int[] instance = new int[1];
 571  0
             int result = ICStart( instance, 0 );
 572  0
             if ( result == 0 ) {
 573  0
                int[] selectionStart = new int[] {
 574   
                   0
 575   
                };
 576  0
                byte[] urlBytes = url.getBytes();
 577  0
                int[] selectionEnd = new int[] {
 578   
                   urlBytes.length
 579   
                };
 580  0
                result = ICLaunchURL( instance[0], new byte[] {
 581   
                   0
 582   
                }, urlBytes, urlBytes.length, selectionStart, selectionEnd );
 583  0
                if ( result == 0 ) {
 584   
                   // Ignore the return value; the URL was launched successfully
 585   
                   // regardless of what happens here.
 586  0
                   ICStop( instance );
 587   
                } else {
 588  0
                   throw new IOException( "Unable to launch URL: " + result );
 589   
                }
 590   
             } else {
 591  0
                throw new IOException(
 592   
                      "Unable to create an Internet Config instance: " + result );
 593   
             }
 594  0
             break;
 595   
          case MRJ_3_1:
 596  0
             try {
 597  0
                openURL.invoke( null, new Object[] {
 598   
                   url
 599   
                } );
 600   
             } catch ( InvocationTargetException ite ) {
 601  0
                throw new IOException(
 602   
                      "InvocationTargetException while calling openURL: "
 603   
                            + ite.getMessage() );
 604   
             } catch ( IllegalAccessException iae ) {
 605  0
                throw new IOException(
 606   
                      "IllegalAccessException while calling openURL: "
 607   
                            + iae.getMessage() );
 608   
             }
 609  0
             break;
 610   
          case WINDOWS_NT:
 611   
          case WINDOWS_9x:
 612   
             // Add quotes around the URL to allow ampersands and other special
 613   
             // characters to work.
 614  0
             Process process = Runtime.getRuntime().exec(
 615   
                   new String[] {
 616   
                         ( String ) browser, FIRST_WINDOWS_PARAMETER,
 617   
                         SECOND_WINDOWS_PARAMETER, THIRD_WINDOWS_PARAMETER,
 618   
                         '"' + url + '"'
 619   
                   } );
 620   
             // This avoids a memory leak on some versions of Java on Windows.
 621   
             // That's hinted at in <http://developer.java.sun.com/developer/qow/archive/68/>.
 622  0
             try {
 623  0
                process.waitFor();
 624  0
                process.exitValue();
 625   
             } catch ( InterruptedException ie ) {
 626  0
                throw new IOException(
 627   
                      "InterruptedException while launching browser: "
 628   
                            + ie.getMessage() );
 629   
             }
 630  0
             break;
 631   
          case OTHER:
 632   
             // Assume that we're on Unix and that Netscape is installed
 633   
 
 634   
             // First, attempt to open the URL in a currently running session of Netscape
 635  0
             process = Runtime.getRuntime().exec(
 636   
                   new String[] {
 637   
                         ( String ) browser,
 638   
                         NETSCAPE_REMOTE_PARAMETER,
 639   
                         NETSCAPE_OPEN_PARAMETER_START + url
 640   
                               + NETSCAPE_OPEN_PARAMETER_END
 641   
                   } );
 642  0
             try {
 643  0
                int exitCode = process.waitFor();
 644  0
                if ( exitCode != 0 ) { // if Netscape was not open
 645  0
                   Runtime.getRuntime().exec( new String[] {
 646   
                         ( String ) browser, url
 647   
                   } );
 648   
                }
 649   
             } catch ( InterruptedException ie ) {
 650  0
                throw new IOException(
 651   
                      "InterruptedException while launching browser: "
 652   
                            + ie.getMessage() );
 653   
             }
 654  0
             break;
 655   
          default:
 656   
             // This should never occur, but if it does, we'll try the simplest thing possible
 657  0
             Runtime.getRuntime().exec( new String[] {
 658   
                   ( String ) browser, url
 659   
             } );
 660  0
             break;
 661   
       }
 662   
    }
 663   
 
 664   
    /**
 665   
     * Methods required for Mac OS X. The presence of native methods does not cause any problems on other platforms.
 666   
     */
 667   
    private native static int ICStart( int[] instance, int signature );
 668   
 
 669   
    private native static int ICStop( int[] instance );
 670   
 
 671   
    private native static int ICLaunchURL( int instance, byte[] hint,
 672   
          byte[] data, int len, int[] selectionStart, int[] selectionEnd );
 673   
 }