Clover coverage report - baseCode - 0.2.5 Coverage timestamp: Tue Apr 12 2005 11:31:58 EDT FRAMES NO FRAMES |
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% |

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 |  |
     }