KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > agent > client > util > BrowserLauncher


1 package com.sslexplorer.agent.client.util;
2
3 import java.io.BufferedReader JavaDoc;
4 import java.io.File JavaDoc;
5 import java.io.InputStream JavaDoc;
6 import java.io.InputStreamReader JavaDoc;
7 import java.io.IOException JavaDoc;
8 import java.lang.reflect.Constructor JavaDoc;
9 import java.lang.reflect.Field JavaDoc;
10 import java.lang.reflect.InvocationTargetException JavaDoc;
11 import java.lang.reflect.Method JavaDoc;
12 import java.text.MessageFormat JavaDoc;
13 import java.util.Vector JavaDoc;
14
15 /**
16  * BrowserLauncher is a class that provides one static method, openURL, which
17  * opens the default web browser for the current user of the system to the given
18  * URL. It may support other protocols depending on the system -- mailto, ftp,
19  * etc. -- but that has not been rigorously tested and is not guaranteed to
20  * work.
21  * <p>
22  * Yes, this is platform-specific code, and yes, it may rely on classes on
23  * certain platforms that are not part of the standard JDK. What we're trying to
24  * do, though, is to take something that's frequently desirable but inherently
25  * platform-specific -- opening a default browser -- and allow programmers (you,
26  * for example) to do so without worrying about dropping into native code or
27  * doing anything else similarly evil.
28  * <p>
29  * Anyway, this code is completely in Java and will run on all JDK 1.1-compliant
30  * systems without modification or a need for additional libraries. All classes
31  * that are required on certain platforms to allow this to run are dynamically
32  * loaded at runtime via reflection and, if not found, will not cause this to do
33  * anything other than returning an error when opening the browser.
34  * <p>
35  * There are certain system requirements for this class, as it's running through
36  * Runtime.exec(), which is Java's way of making a native system call.
37  * Currently, this requires that a Macintosh have a Finder which supports the
38  * GURL event, which is true for Mac OS 8.0 and 8.1 systems that have the
39  * Internet Scripting AppleScript dictionary installed in the Scripting
40  * Additions folder in the Extensions folder (which is installed by default as
41  * far as I know under Mac OS 8.0 and 8.1), and for all Mac OS 8.5 and later
42  * systems. On Windows, it only runs under Win32 systems (Windows 95, 98, and NT
43  * 4.0, as well as later versions of all). On other systems, this drops back
44  * from the inherently platform-sensitive concept of a default browser and
45  * simply attempts to launch Netscape via a shell command.
46  * <p>
47  * This code is Copyright 1999-2002 by Eric Albert (ejalbert@cs.stanford.edu)
48  * and may be redistributed or modified in any form without restrictions as long
49  * as the portion of this comment from this paragraph through the end of the
50  * comment is not removed. The author requests that he be notified of any
51  * application, applet, or other binary that makes use of this code, but that's
52  * more out of curiosity than anything and is not required. This software
53  * includes no warranty. The author is not repsonsible for any loss of data or
54  * functionality or any adverse or unexpected effects of using this software.
55  * <p>
56  * Credits: <br>
57  * Steven Spencer, JavaWorld magazine ( <a
58  * HREF="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java Tip
59  * 66 </a>) <br>
60  * Thanks also to Ron B. Yeh, Eric Shapiro, Ben Engber, Paul Teitlebaum, Andrea
61  * Cantatore, Larry Barowski, Trevor Bedzek, Frank Miedrich, Ron Rabakukk, and
62  * Glenn Vanderburg
63  *
64  * @author Eric Albert ( <a
65  * HREF="mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu </a>)
66  *
67  * <p>
68  * Additional
69  * <p>
70  * <p>
71  * Changes made by Brett Smith ( <a HREF="mailto:brett@3sp.com">brett@3sp,com.
72  * </a> to allow a command to be specified that will always be used. Copyright
73  * 2004 3SP <a HREF="http://3sp.com">3SP </a>.
74  */

75 public class BrowserLauncher {
76
77   /**
78    * The Java virtual machine that we are running on. Actually, in most cases we
79    * only care about the operating system, but some operating systems require us
80    * to switch on the VM.
81    */

82   private static int jvm;
83
84   /** The browser for the system */
85   private static Object JavaDoc browser;
86
87   /** Browser command to always use */
88   private static String JavaDoc browserCommand;
89
90   /**
91    * Caches whether any classes, methods, and fields that are not part of the
92    * JDK and need to be dynamically loaded at runtime loaded successfully.
93    * <p>
94    * Note that if this is <code>false</code>,<code>openURL()</code> will
95    * always return an IOException.
96    */

97   private static boolean loadedWithoutErrors;
98
99   /** The com.apple.mrj.MRJFileUtils class */
100   private static Class JavaDoc mrjFileUtilsClass;
101
102   /** The com.apple.mrj.MRJOSType class */
103   private static Class JavaDoc mrjOSTypeClass;
104
105   /** The com.apple.MacOS.AEDesc class */
106   private static Class JavaDoc aeDescClass;
107
108   /** The <init>(int) method of com.apple.MacOS.AETarget */
109   private static Constructor JavaDoc aeTargetConstructor;
110
111   /** The <init>(int, int, int) method of com.apple.MacOS.AppleEvent */
112   private static Constructor JavaDoc appleEventConstructor;
113
114   /** The <init>(String) method of com.apple.MacOS.AEDesc */
115   private static Constructor JavaDoc aeDescConstructor;
116
117   /** The findFolder method of com.apple.mrj.MRJFileUtils */
118   private static Method JavaDoc findFolder;
119
120   /** The getFileCreator method of com.apple.mrj.MRJFileUtils */
121   private static Method JavaDoc getFileCreator;
122
123   /** The getFileType method of com.apple.mrj.MRJFileUtils */
124   private static Method JavaDoc getFileType;
125
126   /** The openURL method of com.apple.mrj.MRJFileUtils */
127   private static Method JavaDoc openURL;
128
129   /** The makeOSType method of com.apple.MacOS.OSUtils */
130   private static Method JavaDoc makeOSType;
131
132   /** The putParameter method of com.apple.MacOS.AppleEvent */
133   private static Method JavaDoc putParameter;
134
135   /** The sendNoReply method of com.apple.MacOS.AppleEvent */
136   private static Method JavaDoc sendNoReply;
137
138   /** Actually an MRJOSType pointing to the System Folder on a Macintosh */
139   private static Object JavaDoc kSystemFolderType;
140
141   /** The keyDirectObject AppleEvent parameter type */
142   private static Integer JavaDoc keyDirectObject;
143
144   /** The kAutoGenerateReturnID AppleEvent code */
145   private static Integer JavaDoc kAutoGenerateReturnID;
146
147   /** The kAnyTransactionID AppleEvent code */
148   private static Integer JavaDoc kAnyTransactionID;
149
150   /** The linkage object required for JDirect 3 on Mac OS X */
151   private static Object JavaDoc linkage;
152
153   /** The framework to reference on Mac OS X 10.0.x */
154   private static final String JavaDoc JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox"; //$NON-NLS-1$
155

156   /** JVM constant for MRJ 2.0 */
157   private static final int MRJ_2_0 = 0;
158
159   /** JVM constant for MRJ 2.1.x and 2.2.x */
160   private static final int MRJ_2_1 = 1;
161
162   /** JVM constant for Java on Mac OS X 10.0 (MRJ 3.0) */
163   private static final int MRJ_3_0 = 3;
164
165   /** JVM constant for Java 1.3.x on Mac OS X 10.1 and later (MRJ 3.1 and 3.2) */
166   private static final int MRJ_3_1 = 4;
167
168   /** JVM constant for Java 1.4.x and later on Mac OS X */
169   private static final int MRJ_COCOA = 5;
170
171   /** JVM constant for any Windows NT JVM */
172   private static final int WINDOWS_NT = 6;
173
174   /** JVM constant for any Windows 9x JVM */
175   private static final int WINDOWS_9x = 7;
176
177   /** JVM constant for any other platform */
178   private static final int OTHER = -1;
179
180   /**
181    * The file type of the Finder on a Macintosh. Hardcoding "Finder" would keep
182    * non-U.S. English systems from working properly.
183    */

184   private static final String JavaDoc FINDER_TYPE = "FNDR"; //$NON-NLS-1$
185

186   /**
187    * The creator code of the Finder on a Macintosh, which is needed to send
188    * AppleEvents to the application.
189    */

190   private static final String JavaDoc FINDER_CREATOR = "MACS"; //$NON-NLS-1$
191

192   /** The name for the AppleEvent type corresponding to a GetURL event. */
193   private static final String JavaDoc GURL_EVENT = "GURL"; //$NON-NLS-1$
194

195   /**
196    * The first parameter that needs to be passed into Runtime.exec() to open the
197    * default web browser on Windows.
198    */

199   private static final String JavaDoc FIRST_WINDOWS_PARAMETER = "/c"; //$NON-NLS-1$
200

201   /** The second parameter for Runtime.exec() on Windows. */
202   private static final String JavaDoc SECOND_WINDOWS_PARAMETER = "start"; //$NON-NLS-1$
203

204   /**
205    * The third parameter for Runtime.exec() on Windows. This is a "title"
206    * parameter that the command line expects. Setting this parameter allows URLs
207    * containing spaces to work.
208    */

209   private static final String JavaDoc THIRD_WINDOWS_PARAMETER = "\"\""; //$NON-NLS-1$
210

211   /**
212    * The shell parameters for Netscape that opens a given URL in an already-open
213    * copy of Netscape on many command-line systems.
214    */

215   private static final String JavaDoc NETSCAPE_REMOTE_PARAMETER = "-remote"; //$NON-NLS-1$
216
private static final String JavaDoc NETSCAPE_OPEN_PARAMETER_START = "'openURL("; //$NON-NLS-1$
217
private static final String JavaDoc NETSCAPE_OPEN_PARAMETER_END = ")'"; //$NON-NLS-1$
218

219   /**
220    * The message from any exception thrown throughout the initialization
221    * process.
222    */

223   private static String JavaDoc errorMessage;
224
225   /**
226    * An initialization block that determines the operating system and loads the
227    * necessary runtime data.
228    */

229   static {
230     loadedWithoutErrors = true;
231     String JavaDoc osName = System.getProperty("os.name"); //$NON-NLS-1$
232
if (osName.startsWith("Mac OS")) { //$NON-NLS-1$
233
String JavaDoc javaVersion = System.getProperty("java.version"); //$NON-NLS-1$
234
String JavaDoc majorJavaVersion = javaVersion.substring(0, 3);
235       try {
236         double version = Double.valueOf(majorJavaVersion).doubleValue();
237         if (version >= 1.4) {
238           jvm = MRJ_COCOA;
239         }
240       } catch (NumberFormatException JavaDoc nfe) {
241         // Fall through to earlier versions of Java on the Mac.
242
}
243       if (jvm != MRJ_COCOA) {
244         String JavaDoc mrjVersion = System.getProperty("mrj.version"); //$NON-NLS-1$
245
String JavaDoc majorMRJVersion = mrjVersion.substring(0, 3);
246         try {
247           double version = Double.valueOf(majorMRJVersion).doubleValue();
248           if (version == 2) {
249             jvm = MRJ_2_0;
250           } else if (version >= 2.1 && version < 3) {
251             // Assume that all post-2.1 2.x versions of MRJ work the same. MRJ
252
// 2.1 actually
253
// works via Runtime.exec() and 2.2 supports that but has an
254
// openURL() method
255
// as well that we don't use because the Runtime.exec() method works
256
// fine.
257
jvm = MRJ_2_1;
258           } else if (version == 3.0) {
259             jvm = MRJ_3_0;
260           } else if (version >= 3.1) {
261             // Assume that all 3.1 and later versions of MRJ work the same.
262
jvm = MRJ_3_1;
263           } else {
264             loadedWithoutErrors = false;
265             errorMessage = "Unsupported MRJ version: " + version; //$NON-NLS-1$
266
}
267         } catch (NumberFormatException JavaDoc nfe) {
268           loadedWithoutErrors = false;
269           errorMessage = "Invalid MRJ version: " + mrjVersion; //$NON-NLS-1$
270
}
271       }
272     } else if (osName.startsWith("Windows")) { //$NON-NLS-1$
273
if (osName.indexOf("9") != -1 || osName.indexOf("Me") != -1) { //$NON-NLS-1$ //$NON-NLS-2$
274
jvm = WINDOWS_9x;
275       } else {
276         jvm = WINDOWS_NT;
277       }
278     } else {
279       jvm = OTHER;
280     }
281
282     if (loadedWithoutErrors) { // if we haven't hit any errors yet
283
loadedWithoutErrors = loadClasses();
284     }
285   }
286
287   /**
288    * This class should be never be instantiated; this just ensures so.
289    */

290   private BrowserLauncher() {
291   }
292
293   /**
294    * Manually set the browser command. If this is set then none the this command
295    * will <b>always </b> be used.
296    *
297    * @param browserCommand
298    * browser command
299    */

300   public static void setBrowserCommand(String JavaDoc browserCommand) {
301     BrowserLauncher.browserCommand = browserCommand;
302   }
303
304   /**
305    * Split a string into an array taking into account delimiters, quotes
306    * and escapes
307    *
308    * @param str string to split
309    * @param delim delimiter
310    * @param quote quote character
311    * @param escape escape character
312    * @return array
313    */

314
315   public static String JavaDoc[] splitString(String JavaDoc str, char delim, char quote, char escape) {
316     Vector JavaDoc v = new Vector JavaDoc();
317     StringBuffer JavaDoc str1 = new StringBuffer JavaDoc();
318     char ch = ' ';
319     boolean inQuote = false;
320     boolean escaped = false;
321
322     for (int i = 0; i < str.length(); i++) {
323       ch = str.charAt(i);
324
325       if ((escape != -1) && (ch == escape) && !escaped) {
326         escaped = true;
327       } else {
328         if ((quote != -1) && (ch == quote) && !escaped) {
329           inQuote = !inQuote;
330         } else if (!inQuote && (ch == delim && !escaped)) {
331           v.addElement(str1.toString());
332           str1.setLength(0);
333         } else {
334           str1.append(ch);
335         }
336         if (escaped) {
337           escaped = false;
338         }
339       }
340     }
341
342     if (str.length() > 0) {
343       v.addElement(str1.toString());
344
345     }
346     String JavaDoc[] array;
347     array = new String JavaDoc[v.size()];
348     v.copyInto(array);
349
350     return array;
351   }
352
353   /**
354    * Called by a static initializer to load any classes, fields, and methods
355    * required at runtime to locate the user's web browser.
356    *
357    * @return <code>true</code> if all intialization succeeded
358    * <code>false</code> if any portion of the initialization failed
359    */

360   private static boolean loadClasses() {
361     switch (jvm) {
362       case MRJ_2_0 :
363         return loadMRJ20Classes();
364       case MRJ_2_1 :
365         try {
366           mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils"); //$NON-NLS-1$
367
mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType"); //$NON-NLS-1$
368
Field JavaDoc systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType"); //$NON-NLS-1$
369
kSystemFolderType = systemFolderField.get(null);
370           findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class JavaDoc[]{mrjOSTypeClass}); //$NON-NLS-1$
371
getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class JavaDoc[]{File JavaDoc.class}); //$NON-NLS-1$
372
getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class JavaDoc[]{File JavaDoc.class}); //$NON-NLS-1$
373
} catch (ClassNotFoundException JavaDoc cnfe) {
374           errorMessage = cnfe.getMessage();
375           return false;
376         } catch (NoSuchFieldException JavaDoc nsfe) {
377           errorMessage = nsfe.getMessage();
378           return false;
379         } catch (NoSuchMethodException JavaDoc nsme) {
380           errorMessage = nsme.getMessage();
381           return false;
382         } catch (SecurityException JavaDoc se) {
383           errorMessage = se.getMessage();
384           return false;
385         } catch (IllegalAccessException JavaDoc iae) {
386           errorMessage = iae.getMessage();
387           return false;
388         }
389         break;
390       case MRJ_3_0 :
391         try {
392           Class JavaDoc linker = Class.forName("com.apple.mrj.jdirect.Linker"); //$NON-NLS-1$
393
Constructor JavaDoc constructor = linker.getConstructor(new Class JavaDoc[]{Class JavaDoc.class});
394           linkage = constructor.newInstance(new Object JavaDoc[]{BrowserLauncher.class});
395         } catch (ClassNotFoundException JavaDoc cnfe) {
396           errorMessage = cnfe.getMessage();
397           return false;
398         } catch (NoSuchMethodException JavaDoc nsme) {
399           errorMessage = nsme.getMessage();
400           return false;
401         } catch (InvocationTargetException JavaDoc ite) {
402           errorMessage = ite.getMessage();
403           return false;
404         } catch (InstantiationException JavaDoc ie) {
405           errorMessage = ie.getMessage();
406           return false;
407         } catch (IllegalAccessException JavaDoc iae) {
408           errorMessage = iae.getMessage();
409           return false;
410         }
411         break;
412       case MRJ_3_1 :
413       case MRJ_COCOA :
414         String JavaDoc className;
415         if (jvm == MRJ_3_1) {
416           className = "com.apple.mrj.MRJFileUtils"; //$NON-NLS-1$
417
} else {
418           className = "com.apple.eio.FileManager"; //$NON-NLS-1$
419
}
420         try {
421           mrjFileUtilsClass = Class.forName(className);
422           openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class JavaDoc[]{String JavaDoc.class}); //$NON-NLS-1$
423
} catch (ClassNotFoundException JavaDoc cnfe) {
424           errorMessage = cnfe.getMessage();
425           return false;
426         } catch (NoSuchMethodException JavaDoc nsme) {
427           errorMessage = nsme.getMessage();
428           return false;
429         }
430         break;
431       default :
432         break;
433     }
434     return true;
435   }
436
437   /**
438    * Loads the classes, fields, and methods needed when running under MRJ 2.0.
439    * Sets <code>errorMessage</code> if it fails.
440    *
441    * @return <code>true</code> if all operations succeeded; <code>false</code>
442    * otherwise
443    */

444   private static boolean loadMRJ20Classes() {
445     try {
446       Class JavaDoc aeTargetClass = Class.forName("com.apple.MacOS.AETarget"); //$NON-NLS-1$
447
Class JavaDoc osUtilsClass = Class.forName("com.apple.MacOS.OSUtils"); //$NON-NLS-1$
448
Class JavaDoc appleEventClass = Class.forName("com.apple.MacOS.AppleEvent"); //$NON-NLS-1$
449
Class JavaDoc aeClass = Class.forName("com.apple.MacOS.ae"); //$NON-NLS-1$
450
aeDescClass = Class.forName("com.apple.MacOS.AEDesc"); //$NON-NLS-1$
451

452       aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class JavaDoc[]{int.class});
453       appleEventConstructor = appleEventClass.getDeclaredConstructor(new Class JavaDoc[]{int.class, int.class, aeTargetClass, int.class,
454           int.class});
455       aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class JavaDoc[]{String JavaDoc.class});
456
457       makeOSType = osUtilsClass.getDeclaredMethod("makeOSType", new Class JavaDoc[]{String JavaDoc.class}); //$NON-NLS-1$
458
putParameter = appleEventClass.getDeclaredMethod("putParameter", new Class JavaDoc[]{int.class, aeDescClass}); //$NON-NLS-1$
459
sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply", new Class JavaDoc[]{}); //$NON-NLS-1$
460

461       Field JavaDoc keyDirectObjectField = aeClass.getDeclaredField("keyDirectObject"); //$NON-NLS-1$
462
keyDirectObject = (Integer JavaDoc) keyDirectObjectField.get(null);
463       Field JavaDoc autoGenerateReturnIDField = appleEventClass.getDeclaredField("kAutoGenerateReturnID"); //$NON-NLS-1$
464
kAutoGenerateReturnID = (Integer JavaDoc) autoGenerateReturnIDField.get(null);
465       Field JavaDoc anyTransactionIDField = appleEventClass.getDeclaredField("kAnyTransactionID"); //$NON-NLS-1$
466
kAnyTransactionID = (Integer JavaDoc) anyTransactionIDField.get(null);
467     } catch (ClassNotFoundException JavaDoc cnfe) {
468       errorMessage = cnfe.getMessage();
469       return false;
470     } catch (NoSuchMethodException JavaDoc nsme) {
471       errorMessage = nsme.getMessage();
472       return false;
473     } catch (NoSuchFieldException JavaDoc nsfe) {
474       errorMessage = nsfe.getMessage();
475       return false;
476     } catch (IllegalAccessException JavaDoc iae) {
477       errorMessage = iae.getMessage();
478       return false;
479     }
480     return true;
481   }
482
483   /**
484    * Attempts to locate the default web browser on the local system. Caches the
485    * result so it only locates the browser once for each use of this class per
486    * JVM instance.
487    *
488    * @return The browser for the system. Note that this may not be what you
489    * would consider to be a standard web browser; instead, it's the
490    * application that gets called to open the default web browser. In
491    * some cases this will be a non-String object that provides the means
492    * of calling the default browser.
493    */

494   private static Object JavaDoc locateBrowser() {
495     if (browser != null) {
496       return browser;
497     }
498     switch (jvm) {
499       case MRJ_2_0 :
500         try {
501           Integer JavaDoc finderCreatorCode = (Integer JavaDoc) makeOSType.invoke(null, new Object JavaDoc[]{FINDER_CREATOR});
502           Object JavaDoc aeTarget = aeTargetConstructor.newInstance(new Object JavaDoc[]{finderCreatorCode});
503           Integer JavaDoc gurlType = (Integer JavaDoc) makeOSType.invoke(null, new Object JavaDoc[]{GURL_EVENT});
504           Object JavaDoc appleEvent = appleEventConstructor.newInstance(new Object JavaDoc[]{gurlType, gurlType, aeTarget, kAutoGenerateReturnID,
505               kAnyTransactionID});
506           // Don't set browser = appleEvent because then the next time we call
507
// locateBrowser(), we'll get the same AppleEvent, to which we'll
508
// already have
509
// added the relevant parameter. Instead, regenerate the AppleEvent
510
// every time.
511
// There's probably a way to do this better; if any has any ideas,
512
// please let
513
// me know.
514
return appleEvent;
515         } catch (IllegalAccessException JavaDoc iae) {
516           browser = null;
517           errorMessage = iae.getMessage();
518           return browser;
519         } catch (InstantiationException JavaDoc ie) {
520           browser = null;
521           errorMessage = ie.getMessage();
522           return browser;
523         } catch (InvocationTargetException JavaDoc ite) {
524           browser = null;
525           errorMessage = ite.getMessage();
526           return browser;
527         }
528       case MRJ_2_1 :
529         File JavaDoc systemFolder;
530         try {
531           systemFolder = (File JavaDoc) findFolder.invoke(null, new Object JavaDoc[]{kSystemFolderType});
532         } catch (IllegalArgumentException JavaDoc iare) {
533           browser = null;
534           errorMessage = iare.getMessage();
535           return browser;
536         } catch (IllegalAccessException JavaDoc iae) {
537           browser = null;
538           errorMessage = iae.getMessage();
539           return browser;
540         } catch (InvocationTargetException JavaDoc ite) {
541           browser = null;
542           errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage(); //$NON-NLS-1$
543
return browser;
544         }
545         String JavaDoc[] systemFolderFiles = systemFolder.list();
546         // Avoid a FilenameFilter because that can't be stopped mid-list
547
for (int i = 0; i < systemFolderFiles.length; i++) {
548           try {
549             File JavaDoc file = new File JavaDoc(systemFolder, systemFolderFiles[i]);
550             if (!file.isFile()) {
551               continue;
552             }
553             // We're looking for a file with a creator code of 'MACS' and
554
// a type of 'FNDR'. Only requiring the type results in non-Finder
555
// applications being picked up on certain Mac OS 9 systems,
556
// especially German ones, and sending a GURL event to those
557
// applications results in a logout under Multiple Users.
558
Object JavaDoc fileType = getFileType.invoke(null, new Object JavaDoc[]{file});
559             if (FINDER_TYPE.equals(fileType.toString())) {
560               Object JavaDoc fileCreator = getFileCreator.invoke(null, new Object JavaDoc[]{file});
561               if (FINDER_CREATOR.equals(fileCreator.toString())) {
562                 browser = file.toString(); // Actually the Finder, but that's OK
563
return browser;
564               }
565             }
566           } catch (IllegalArgumentException JavaDoc iare) {
567             browser = null;
568             errorMessage = iare.getMessage();
569             return null;
570           } catch (IllegalAccessException JavaDoc iae) {
571             browser = null;
572             errorMessage = iae.getMessage();
573             return browser;
574           } catch (InvocationTargetException JavaDoc ite) {
575             browser = null;
576             errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage(); //$NON-NLS-1$
577
return browser;
578           }
579         }
580         browser = null;
581         break;
582       case MRJ_3_0 :
583       case MRJ_3_1 :
584         browser = ""; // Return something non-null //$NON-NLS-1$
585
break;
586       case WINDOWS_NT :
587         browser = "cmd.exe"; //$NON-NLS-1$
588
break;
589       case WINDOWS_9x :
590         browser = "command.com"; //$NON-NLS-1$
591
break;
592       case OTHER :
593       default :
594         // On systems other than Windows and the Mac, we try via a rather Unix-
595
// specific hack to read the BROWSER environment variable
596
// <http://tuxedo.org/~esr/BROWSER/>. If we can't read that variable or
597
// it isn't set, we use Netscape.
598
// Note: This is commented out for now. It'll work soon.
599
browser = getEnvironmentBrowser();
600         if (browser == null) {
601           browser = "netscape"; //$NON-NLS-1$
602
}
603         break;
604     }
605     return browser;
606   }
607
608   /**
609    * Attempts to open the default web browser to the given URL.
610    *
611    * @param url
612    * The URL to open
613    * @throws IOException
614    * If the web browser could not be located or does not run
615    */

616   public static void openURL(String JavaDoc url) throws IOException JavaDoc {
617     if (!loadedWithoutErrors) {
618       throw new IOException JavaDoc(MessageFormat.format(Messages.getString("BrowserLauncher.exceptionFindingBrowser"), new Object JavaDoc[] { errorMessage })); //$NON-NLS-1$
619
}
620
621
622     if(browserCommand != null) {
623       String JavaDoc[] cmd = splitString(browserCommand, ' ', '"', '\\');
624       String JavaDoc[] cmde = new String JavaDoc[cmd.length + 1];
625       System.arraycopy(cmd, 0, cmde, 0 , cmd.length);
626       cmde[cmd.length] = url;
627       Runtime.getRuntime().exec(cmde);
628       return;
629     }
630
631     Object JavaDoc browser = locateBrowser();
632     if (browser == null) {
633       throw new IOException JavaDoc(MessageFormat.format(Messages.getString("BrowserLauncher.unableToLocateBrowser"), new Object JavaDoc[] { errorMessage } ) ); //$NON-NLS-1$
634
}
635
636     switch (jvm) {
637       case MRJ_2_0 :
638         Object JavaDoc aeDesc = null;
639         try {
640           aeDesc = aeDescConstructor.newInstance(new Object JavaDoc[]{url});
641           putParameter.invoke(browser, new Object JavaDoc[]{keyDirectObject, aeDesc});
642           sendNoReply.invoke(browser, new Object JavaDoc[]{});
643         } catch (InvocationTargetException JavaDoc ite) {
644           throw new IOException JavaDoc(MessageFormat.format(Messages.getString("BrowserLauncher.invocationTargetException"), new Object JavaDoc[] { ite.getMessage() } ) ); //$NON-NLS-1$
645
} catch (IllegalAccessException JavaDoc iae) {
646           throw new IOException JavaDoc(MessageFormat.format(Messages.getString("BrowserLauncher.illegalAccess"), new Object JavaDoc[] { iae.getMessage() } )); //$NON-NLS-1$
647
} catch (InstantiationException JavaDoc ie) {
648           throw new IOException JavaDoc(MessageFormat.format(Messages.getString("BrowserLauncher.instantiation"), new Object JavaDoc[] { ie.getMessage() } )); //$NON-NLS-1$
649
} finally {
650           aeDesc = null; // Encourage it to get disposed if it was created
651
browser = null; // Ditto
652
}
653         break;
654       case MRJ_2_1 :
655         Runtime.getRuntime().exec(new String JavaDoc[]{(String JavaDoc) browser, url});
656         break;
657       case MRJ_3_0 :
658         int[] instance = new int[1];
659         int result = ICStart(instance, 0);
660         if (result == 0) {
661           int[] selectionStart = new int[]{0};
662           byte[] urlBytes = url.getBytes();
663           int[] selectionEnd = new int[]{urlBytes.length};
664           result = ICLaunchURL(instance[0], new byte[]{0}, urlBytes, urlBytes.length, selectionStart, selectionEnd);
665           if (result == 0) {
666             // Ignore the return value; the URL was launched successfully
667
// regardless of what happens here.
668
ICStop(instance);
669           } else {
670             throw new IOException JavaDoc(MessageFormat.format(Messages.getString("BrowserLauncher.cannotLaunchURL"), new Object JavaDoc[] { new Integer JavaDoc(result) } )); //$NON-NLS-1$
671
}
672         } else {
673           throw new IOException JavaDoc(MessageFormat.format(Messages.getString("BrowserLauncher.cannotCreateNetConfg"), new Object JavaDoc[] { new Integer JavaDoc(result) } ) ); //$NON-NLS-1$
674
}
675         break;
676       case MRJ_3_1 :
677       case MRJ_COCOA :
678         try {
679           openURL.invoke(null, new Object JavaDoc[]{url});
680         } catch (InvocationTargetException JavaDoc ite) {
681           throw new IOException JavaDoc(MessageFormat.format(Messages.getString("BrowserLauncher.cannotOpenURL"), new Object JavaDoc[] { ite.getMessage() } ) ); //$NON-NLS-1$
682
} catch (IllegalAccessException JavaDoc iae) {
683           throw new IOException JavaDoc(MessageFormat.format(Messages.getString("BrowserLauncher.ilegalAccessOpeningURL"), new Object JavaDoc[] { iae.getMessage() } ) ); //$NON-NLS-1$
684
}
685         break;
686       case WINDOWS_NT :
687       case WINDOWS_9x :
688         // Add quotes around the URL to allow ampersands and other special
689
// characters to work.
690
String JavaDoc[] arguments;
691         if (jvm == WINDOWS_9x) {
692           arguments = new String JavaDoc[]{(String JavaDoc) browser, FIRST_WINDOWS_PARAMETER, SECOND_WINDOWS_PARAMETER, null};
693         } else {
694           arguments = new String JavaDoc[]{(String JavaDoc) browser, FIRST_WINDOWS_PARAMETER, SECOND_WINDOWS_PARAMETER, THIRD_WINDOWS_PARAMETER,
695               null};
696         }
697         arguments[arguments.length - 1] = '"' + url + '"';
698         Process JavaDoc process = Runtime.getRuntime().exec(arguments);
699         // This avoids a memory leak on some versions of Java on Windows.
700
// That's hinted at in
701
// <http://developer.java.sun.com/developer/qow/archive/68/>.
702
try {
703           process.waitFor();
704           process.exitValue();
705         } catch (InterruptedException JavaDoc ie) {
706           throw new IOException JavaDoc(Messages.getString("BrowserLauncher.interruptedLaunchingBrowser") + ie.getMessage()); //$NON-NLS-1$
707
}
708         break;
709       case OTHER :
710         // Assume that we're on Unix and that Netscape is installed
711

712         // Attempt to open the URL in a currently running session of Netscape
713
process = Runtime.getRuntime().exec(
714             new String JavaDoc[]{(String JavaDoc) browser, NETSCAPE_REMOTE_PARAMETER,
715                 NETSCAPE_OPEN_PARAMETER_START + url + NETSCAPE_OPEN_PARAMETER_END});
716         try {
717           int exitCode = process.waitFor();
718           if (exitCode != 0) { // if Netscape was not open
719
Runtime.getRuntime().exec(new String JavaDoc[]{(String JavaDoc) browser, url});
720           }
721         } catch (InterruptedException JavaDoc ie) {
722           throw new IOException JavaDoc(MessageFormat.format(Messages.getString("BrowserLauncher.interruptedLaunchingBrowser"), new Object JavaDoc[] { ie.getMessage() } ) ); //$NON-NLS-1$
723
}
724         break;
725       default :
726         // This should never occur, but if it does, we'll try the simplest thing
727
// possible
728
Runtime.getRuntime().exec(new String JavaDoc[]{(String JavaDoc) browser, url});
729         break;
730     }
731   }
732
733   /**
734    * Tries to read the BROWSER environment variable, which should be set to the
735    * absolute path of the user's preferred web browser as proposed at
736    * <http://tuxedo.org/~esr/BROWSER/>.
737    *
738    * @return The value of the BROWSER environment variable, or null if the
739    * variable does not exist or can't be read.
740    */

741   private static String JavaDoc getEnvironmentBrowser() {
742     String JavaDoc browser = null;
743     try {
744       String JavaDoc[] echoParams = {"/bin/sh", "-c", "echo ${BROWSER:-netscape}"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
745
Process JavaDoc echoProcess = Runtime.getRuntime().exec(echoParams);
746       InputStream JavaDoc echoStream = echoProcess.getInputStream();
747       BufferedReader JavaDoc echoReader = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(echoStream));
748       browser = echoReader.readLine();
749       echoReader.close();
750     } catch (Throwable JavaDoc t) {
751       // If anything goes wrong, we'll return null.
752
}
753     return browser;
754   }
755
756   /**
757    * Methods required for Mac OS X 10.0.x. The presence of native methods does
758    * not cause any problems on other platforms.
759    */

760   private native static int ICStart(int[] instance, int signature);
761   private native static int ICStop(int[] instance);
762   private native static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len, int[] selectionStart, int[] selectionEnd);
763 }
764
Popular Tags