KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > apollo > dev > browser > albert > BrowserLauncher


1 /*
2 ** Apollo - Test Skeleton Toolkit for Web Start/JNLP
3 ** Copyright (c) 2001, 2002, 2003 by Gerald Bauer
4 **
5 ** This program is free software.
6 **
7 ** You may redistribute it and/or modify it under the terms of the GNU
8 ** General Public License as published by the Free Software Foundation.
9 ** Version 2 of the license should be included with this distribution in
10 ** the file LICENSE, as well as License.html. If the license is not
11 ** included with this distribution, you may find a copy at the FSF web
12 ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
13 ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.
14 **
15 ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
16 ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
17 ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
18 ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
19 ** REDISTRIBUTION OF THIS SOFTWARE.
20 **
21 */

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

87 public class BrowserLauncher
88 {
89
90    /**
91     * The creator code of the Finder on a Macintosh, which is needed to send
92     * AppleEvents to the application.
93     */

94    private final static String JavaDoc FINDER_CREATOR = "MACS";
95
96    /**
97     * The file type of the Finder on a Macintosh. Hardcoding "Finder" would
98     * keep non-U.S. English systems from working properly.
99     */

100    private final static String JavaDoc FINDER_TYPE = "FNDR";
101
102    /**
103     * The first parameter that needs to be passed into Runtime.exec() to open
104     * the default web browser on Windows.
105     */

106    private final static String JavaDoc FIRST_WINDOWS_PARAMETER = "/c";
107
108    /**
109     * The name for the AppleEvent type corresponding to a GetURL event.
110     */

111    private final static String JavaDoc GURL_EVENT = "GURL";
112
113    /**
114     * The framework to reference on Mac OS X
115     */

116    private final static String JavaDoc JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
117
118    /**
119     * JVM constant for MRJ 2.0
120     */

121    private final static int MRJ_2_0 = 0;
122
123    /**
124     * JVM constant for MRJ 2.1 or later
125     */

126    private final static int MRJ_2_1 = 1;
127
128    /**
129     * JVM constant for Java on Mac OS X 10.0 (MRJ 3.0)
130     */

131    private final static int MRJ_3_0 = 3;
132
133    /**
134     * JVM constant for MRJ 3.1
135     */

136    private final static int MRJ_3_1 = 4;
137    private final static String JavaDoc NETSCAPE_OPEN_PARAMETER_END = ")'";
138    private final static String JavaDoc NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
139
140    /**
141     * The shell parameters for Netscape that opens a given URL in an
142     * already-open copy of Netscape on many command-line systems.
143     */

144    private final static String JavaDoc NETSCAPE_REMOTE_PARAMETER = "-remote";
145
146    /**
147     * JVM constant for any other platform
148     */

149    private final static int OTHER = -1;
150
151    /**
152     * The second parameter for Runtime.exec() on Windows.
153     */

154    private final static String JavaDoc SECOND_WINDOWS_PARAMETER = "start";
155
156    /**
157     * The third parameter for Runtime.exec() on Windows. This is a "title"
158     * parameter that the command line expects. Setting this parameter allows
159     * URLs containing spaces to work.
160     */

161    private final static String JavaDoc THIRD_WINDOWS_PARAMETER = "\"\"";
162
163    /**
164     * JVM constant for any Windows 9x JVM
165     */

166    private final static int WINDOWS_9x = 6;
167
168    /**
169     * JVM constant for any Windows NT JVM
170     */

171    private final static int WINDOWS_NT = 5;
172
173    /**
174     * The com.apple.MacOS.AEDesc class
175     */

176    private static Class JavaDoc aeDescClass;
177
178    /**
179     * The <init>(String) method of com.apple.MacOS.AEDesc
180     */

181    private static Constructor JavaDoc aeDescConstructor;
182
183    /**
184     * The <init>(int) method of com.apple.MacOS.AETarget
185     */

186    private static Constructor JavaDoc aeTargetConstructor;
187
188    /**
189     * The <init>(int, int, int) method of com.apple.MacOS.AppleEvent
190     */

191    private static Constructor JavaDoc appleEventConstructor;
192
193    /**
194     * The browser for the system
195     */

196    private static Object JavaDoc browser;
197
198    /**
199     * The message from any exception thrown throughout the initialization
200     * process.
201     */

202    private static String JavaDoc errorMessage;
203
204    /**
205     * The findFolder method of com.apple.mrj.MRJFileUtils
206     */

207    private static Method JavaDoc findFolder;
208
209    /**
210     * The getFileCreator method of com.apple.mrj.MRJFileUtils
211     */

212    private static Method JavaDoc getFileCreator;
213
214    /**
215     * The getFileType method of com.apple.mrj.MRJFileUtils
216     */

217    private static Method JavaDoc getFileType;
218
219    /**
220     * The Java virtual machine that we are running on. Actually, in most cases
221     * we only care about the operating system, but some operating systems
222     * require us to switch on the VM.
223     */

224    private static int jvm;
225
226    /**
227     * The kAnyTransactionID AppleEvent code
228     */

229    private static Integer JavaDoc kAnyTransactionID;
230
231    /**
232     * The kAutoGenerateReturnID AppleEvent code
233     */

234    private static Integer JavaDoc kAutoGenerateReturnID;
235
236    /**
237     * Actually an MRJOSType pointing to the System Folder on a Macintosh
238     */

239    private static Object JavaDoc kSystemFolderType;
240
241    /**
242     * The keyDirectObject AppleEvent parameter type
243     */

244    private static Integer JavaDoc keyDirectObject;
245
246    /**
247     * The linkage object required for JDirect 3 on Mac OS X.
248     */

249    private static Object JavaDoc linkage;
250
251    /**
252     * Caches whether any classes, methods, and fields that are not part of the
253     * JDK and need to be dynamically loaded at runtime loaded successfully. <p>
254     *
255     * Note that if this is <code>false</code>, <code>openURL()</code> will
256     * always return an IOException.
257     */

258    private static boolean loadedWithoutErrors;
259
260    /**
261     * The makeOSType method of com.apple.MacOS.OSUtils
262     */

263    private static Method JavaDoc makeOSType;
264
265    /**
266     * The com.apple.mrj.MRJFileUtils class
267     */

268    private static Class JavaDoc mrjFileUtilsClass;
269
270    /**
271     * The com.apple.mrj.MRJOSType class
272     */

273    private static Class JavaDoc mrjOSTypeClass;
274
275    /**
276     * The openURL method of com.apple.mrj.MRJFileUtils
277     */

278    private static Method JavaDoc openURL;
279
280    /**
281     * The putParameter method of com.apple.MacOS.AppleEvent
282     */

283    private static Method JavaDoc putParameter;
284
285    /**
286     * The sendNoReply method of com.apple.MacOS.AppleEvent
287     */

288    private static Method JavaDoc sendNoReply;
289
290    /**
291     * This class should be never be instantiated; this just ensures so.
292     */

293    private BrowserLauncher() { }
294
295    /**
296     * Attempts to open the default web browser to the given URL.
297     *
298     *@param url The URL to open
299     *@throws IOException If the web browser could not be located or does not
300     * run
301     */

302    public static void openURL( String JavaDoc url ) throws IOException JavaDoc
303    {
304       if( !loadedWithoutErrors )
305       {
306          throw new IOException JavaDoc( "Exception in finding browser: " + errorMessage );
307       }
308       Object JavaDoc browser = locateBrowser();
309       if( browser == null )
310       {
311          throw new IOException JavaDoc( "Unable to locate browser: " + errorMessage );
312       }
313
314       switch ( jvm )
315       {
316          case MRJ_2_0:
317             Object JavaDoc aeDesc = null;
318             try
319             {
320                aeDesc = aeDescConstructor.newInstance( new Object JavaDoc[]{url} );
321                putParameter.invoke( browser, new Object JavaDoc[]{keyDirectObject, aeDesc} );
322                sendNoReply.invoke( browser, new Object JavaDoc[]{} );
323             }
324             catch( InvocationTargetException JavaDoc ite )
325             {
326                throw new IOException JavaDoc( "InvocationTargetException while creating AEDesc: " + ite.getMessage() );
327             }
328             catch( IllegalAccessException JavaDoc iae )
329             {
330                throw new IOException JavaDoc( "IllegalAccessException while building AppleEvent: " + iae.getMessage() );
331             }
332             catch( InstantiationException JavaDoc ie )
333             {
334                throw new IOException JavaDoc( "InstantiationException while creating AEDesc: " + ie.getMessage() );
335             }
336             finally
337             {
338                aeDesc = null;
339                // Encourage it to get disposed if it was created
340
browser = null;
341                // Ditto
342
}
343             break;
344          case MRJ_2_1:
345             Runtime.getRuntime().exec( new String JavaDoc[]{( String JavaDoc ) browser, url} );
346             break;
347          case MRJ_3_0:
348             int[] instance = new int[1];
349             int result = ICStart( instance, 0 );
350             if( result == 0 )
351             {
352                int[] selectionStart = new int[]{0};
353                byte[] urlBytes = url.getBytes();
354                int[] selectionEnd = new int[]{urlBytes.length};
355                result = ICLaunchURL( instance[0], new byte[]{0}, urlBytes,
356                      urlBytes.length, selectionStart,
357                      selectionEnd );
358                if( result == 0 )
359                {
360                   // Ignore the return value; the URL was launched successfully
361
// regardless of what happens here.
362
ICStop( instance );
363                }
364                else
365                {
366                   throw new IOException JavaDoc( "Unable to launch URL: " + result );
367                }
368             }
369             else
370             {
371                throw new IOException JavaDoc( "Unable to create an Internet Config instance: " + result );
372             }
373             break;
374          case MRJ_3_1:
375             try
376             {
377                openURL.invoke( null, new Object JavaDoc[]{url} );
378             }
379             catch( InvocationTargetException JavaDoc ite )
380             {
381                throw new IOException JavaDoc( "InvocationTargetException while calling openURL: " + ite.getMessage() );
382             }
383             catch( IllegalAccessException JavaDoc iae )
384             {
385                throw new IOException JavaDoc( "IllegalAccessException while calling openURL: " + iae.getMessage() );
386             }
387             break;
388          case WINDOWS_NT:
389          case WINDOWS_9x:
390             // Add quotes around the URL to allow ampersands and other special
391
// characters to work.
392
Process JavaDoc process = Runtime.getRuntime().exec( new String JavaDoc[]{( String JavaDoc ) browser,
393                   FIRST_WINDOWS_PARAMETER,
394                   SECOND_WINDOWS_PARAMETER,
395                   THIRD_WINDOWS_PARAMETER,
396                   '"' + url + '"'} );
397             // This avoids a memory leak on some versions of Java on Windows.
398
// That's hinted at in <http://developer.java.sun.com/developer/qow/archive/68/>.
399
try
400             {
401                process.waitFor();
402                process.exitValue();
403             }
404             catch( InterruptedException JavaDoc ie )
405             {
406                throw new IOException JavaDoc( "InterruptedException while launching browser: " + ie.getMessage() );
407             }
408             break;
409          case OTHER:
410             // Assume that we're on Unix and that Netscape is installed
411

412             // First, attempt to open the URL in a currently running session of Netscape
413
process = Runtime.getRuntime().exec( new String JavaDoc[]{( String JavaDoc ) browser,
414                   NETSCAPE_REMOTE_PARAMETER,
415                   NETSCAPE_OPEN_PARAMETER_START +
416                   url +
417                   NETSCAPE_OPEN_PARAMETER_END} );
418             try
419             {
420                int exitCode = process.waitFor();
421                if( exitCode != 0 )
422                {
423                   // if Netscape was not open
424
Runtime.getRuntime().exec( new String JavaDoc[]{( String JavaDoc ) browser, url} );
425                }
426             }
427             catch( InterruptedException JavaDoc ie )
428             {
429                throw new IOException JavaDoc( "InterruptedException while launching browser: " + ie.getMessage() );
430             }
431             break;
432          default:
433             // This should never occur, but if it does, we'll try the simplest thing possible
434
Runtime.getRuntime().exec( new String JavaDoc[]{( String JavaDoc ) browser, url} );
435             break;
436       }
437    }
438
439    private native static int ICLaunchURL( int instance, byte[] hint, byte[] data, int len,
440          int[] selectionStart, int[] selectionEnd );
441
442    /**
443     * Methods required for Mac OS X. The presence of native methods does not
444     * cause any problems on other platforms.
445     */

446    private native static int ICStart( int[] instance, int signature );
447
448    private native static int ICStop( int[] instance );
449
450    /**
451     * Called by a static initializer to load any classes, fields, and methods
452     * required at runtime to locate the user's web browser.
453     *
454     *@return <code>true</code> if all intialization succeeded <code>false</code>
455     * if any portion of the initialization failed
456     */

457    private static boolean loadClasses()
458    {
459       switch ( jvm )
460       {
461          case MRJ_2_0:
462             try
463             {
464                Class JavaDoc aeTargetClass = Class.forName( "com.apple.MacOS.AETarget" );
465                Class JavaDoc osUtilsClass = Class.forName( "com.apple.MacOS.OSUtils" );
466                Class JavaDoc appleEventClass = Class.forName( "com.apple.MacOS.AppleEvent" );
467                Class JavaDoc aeClass = Class.forName( "com.apple.MacOS.ae" );
468                aeDescClass = Class.forName( "com.apple.MacOS.AEDesc" );
469
470                aeTargetConstructor = aeTargetClass.getDeclaredConstructor( new Class JavaDoc[]{int.class} );
471                appleEventConstructor = appleEventClass.getDeclaredConstructor( new Class JavaDoc[]{int.class, int.class, aeTargetClass, int.class, int.class} );
472                aeDescConstructor = aeDescClass.getDeclaredConstructor( new Class JavaDoc[]{String JavaDoc.class} );
473
474                makeOSType = osUtilsClass.getDeclaredMethod( "makeOSType", new Class JavaDoc[]{String JavaDoc.class} );
475                putParameter = appleEventClass.getDeclaredMethod( "putParameter", new Class JavaDoc[]{int.class, aeDescClass} );
476                sendNoReply = appleEventClass.getDeclaredMethod( "sendNoReply", new Class JavaDoc[]{} );
477
478                Field JavaDoc keyDirectObjectField = aeClass.getDeclaredField( "keyDirectObject" );
479                keyDirectObject = ( Integer JavaDoc ) keyDirectObjectField.get( null );
480                Field JavaDoc autoGenerateReturnIDField = appleEventClass.getDeclaredField( "kAutoGenerateReturnID" );
481                kAutoGenerateReturnID = ( Integer JavaDoc ) autoGenerateReturnIDField.get( null );
482                Field JavaDoc anyTransactionIDField = appleEventClass.getDeclaredField( "kAnyTransactionID" );
483                kAnyTransactionID = ( Integer JavaDoc ) anyTransactionIDField.get( null );
484             }
485             catch( ClassNotFoundException JavaDoc cnfe )
486             {
487                errorMessage = cnfe.getMessage();
488                return false;
489             }
490             catch( NoSuchMethodException JavaDoc nsme )
491             {
492                errorMessage = nsme.getMessage();
493                return false;
494             }
495             catch( NoSuchFieldException JavaDoc nsfe )
496             {
497                errorMessage = nsfe.getMessage();
498                return false;
499             }
500             catch( IllegalAccessException JavaDoc iae )
501             {
502                errorMessage = iae.getMessage();
503                return false;
504             }
505             break;
506          case MRJ_2_1:
507             try
508             {
509                mrjFileUtilsClass = Class.forName( "com.apple.mrj.MRJFileUtils" );
510                mrjOSTypeClass = Class.forName( "com.apple.mrj.MRJOSType" );
511                Field JavaDoc systemFolderField = mrjFileUtilsClass.getDeclaredField( "kSystemFolderType" );
512                kSystemFolderType = systemFolderField.get( null );
513                findFolder = mrjFileUtilsClass.getDeclaredMethod( "findFolder", new Class JavaDoc[]{mrjOSTypeClass} );
514                getFileCreator = mrjFileUtilsClass.getDeclaredMethod( "getFileCreator", new Class JavaDoc[]{File JavaDoc.class} );
515                getFileType = mrjFileUtilsClass.getDeclaredMethod( "getFileType", new Class JavaDoc[]{File JavaDoc.class} );
516             }
517             catch( ClassNotFoundException JavaDoc cnfe )
518             {
519                errorMessage = cnfe.getMessage();
520                return false;
521             }
522             catch( NoSuchFieldException JavaDoc nsfe )
523             {
524                errorMessage = nsfe.getMessage();
525                return false;
526             }
527             catch( NoSuchMethodException JavaDoc nsme )
528             {
529                errorMessage = nsme.getMessage();
530                return false;
531             }
532             catch( SecurityException JavaDoc se )
533             {
534                errorMessage = se.getMessage();
535                return false;
536             }
537             catch( IllegalAccessException JavaDoc iae )
538             {
539                errorMessage = iae.getMessage();
540                return false;
541             }
542             break;
543          case MRJ_3_0:
544             try
545             {
546                Class JavaDoc linker = Class.forName( "com.apple.mrj.jdirect.Linker" );
547                Constructor JavaDoc constructor = linker.getConstructor( new Class JavaDoc[]{Class JavaDoc.class} );
548                linkage = constructor.newInstance( new Object JavaDoc[]{BrowserLauncher.class} );
549             }
550             catch( ClassNotFoundException JavaDoc cnfe )
551             {
552                errorMessage = cnfe.getMessage();
553                return false;
554             }
555             catch( NoSuchMethodException JavaDoc nsme )
556             {
557                errorMessage = nsme.getMessage();
558                return false;
559             }
560             catch( InvocationTargetException JavaDoc ite )
561             {
562                errorMessage = ite.getMessage();
563                return false;
564             }
565             catch( InstantiationException JavaDoc ie )
566             {
567                errorMessage = ie.getMessage();
568                return false;
569             }
570             catch( IllegalAccessException JavaDoc iae )
571             {
572                errorMessage = iae.getMessage();
573                return false;
574             }
575             break;
576          case MRJ_3_1:
577             try
578             {
579                mrjFileUtilsClass = Class.forName( "com.apple.mrj.MRJFileUtils" );
580                openURL = mrjFileUtilsClass.getDeclaredMethod( "openURL", new Class JavaDoc[]{String JavaDoc.class} );
581             }
582             catch( ClassNotFoundException JavaDoc cnfe )
583             {
584                errorMessage = cnfe.getMessage();
585                return false;
586             }
587             catch( NoSuchMethodException JavaDoc nsme )
588             {
589                errorMessage = nsme.getMessage();
590                return false;
591             }
592             break;
593          default:
594             break;
595       }
596       return true;
597    }
598
599    /**
600     * Attempts to locate the default web browser on the local system. Caches
601     * results so it only locates the browser once for each use of this class
602     * per JVM instance.
603     *
604     *@return The browser for the system. Note that this may not be what you
605     * would consider to be a standard web browser; instead, it's the
606     * application that gets called to open the default web browser. In some
607     * cases, this will be a non-String object that provides the means of
608     * calling the default browser.
609     */

610    private static Object JavaDoc locateBrowser()
611    {
612       if( browser != null )
613       {
614          return browser;
615       }
616       switch ( jvm )
617       {
618          case MRJ_2_0:
619             try
620             {
621                Integer JavaDoc finderCreatorCode = ( Integer JavaDoc ) makeOSType.invoke( null, new Object JavaDoc[]{FINDER_CREATOR} );
622                Object JavaDoc aeTarget = aeTargetConstructor.newInstance( new Object JavaDoc[]{finderCreatorCode} );
623                Integer JavaDoc gurlType = ( Integer JavaDoc ) makeOSType.invoke( null, new Object JavaDoc[]{GURL_EVENT} );
624                Object JavaDoc appleEvent = appleEventConstructor.newInstance( new Object JavaDoc[]{gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID} );
625                // Don't set browser = appleEvent because then the next time we call
626
// locateBrowser(), we'll get the same AppleEvent, to which we'll already have
627
// added the relevant parameter. Instead, regenerate the AppleEvent every time.
628
// There's probably a way to do this better; if any has any ideas, please let
629
// me know.
630
return appleEvent;
631             }
632             catch( IllegalAccessException JavaDoc iae )
633             {
634                browser = null;
635                errorMessage = iae.getMessage();
636                return browser;
637             }
638             catch( InstantiationException JavaDoc ie )
639             {
640                browser = null;
641                errorMessage = ie.getMessage();
642                return browser;
643             }
644             catch( InvocationTargetException JavaDoc ite )
645             {
646                browser = null;
647                errorMessage = ite.getMessage();
648                return browser;
649             }
650          case MRJ_2_1:
651             File JavaDoc systemFolder;
652             try
653             {
654                systemFolder = ( File JavaDoc ) findFolder.invoke( null, new Object JavaDoc[]{kSystemFolderType} );
655             }
656             catch( IllegalArgumentException JavaDoc iare )
657             {
658                browser = null;
659                errorMessage = iare.getMessage();
660                return browser;
661             }
662             catch( IllegalAccessException JavaDoc iae )
663             {
664                browser = null;
665                errorMessage = iae.getMessage();
666                return browser;
667             }
668             catch( InvocationTargetException JavaDoc ite )
669             {
670                browser = null;
671                errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
672                return browser;
673             }
674             String JavaDoc[] systemFolderFiles = systemFolder.list();
675             // Avoid a FilenameFilter because that can't be stopped mid-list
676
for( int i = 0; i < systemFolderFiles.length; i++ )
677             {
678                try
679                {
680                   File JavaDoc file = new File JavaDoc( systemFolder, systemFolderFiles[i] );
681                   if( !file.isFile() )
682                   {
683                      continue;
684                   }
685                   // We're looking for a file with a creator code of 'MACS' and
686
// a type of 'FNDR'. Only requiring the type results in non-Finder
687
// applications being picked up on certain Mac OS 9 systems,
688
// especially German ones, and sending a GURL event to those
689
// applications results in a logout under Multiple Users.
690
Object JavaDoc fileType = getFileType.invoke( null, new Object JavaDoc[]{file} );
691                   if( FINDER_TYPE.equals( fileType.toString() ) )
692                   {
693                      Object JavaDoc fileCreator = getFileCreator.invoke( null, new Object JavaDoc[]{file} );
694                      if( FINDER_CREATOR.equals( fileCreator.toString() ) )
695                      {
696                         browser = file.toString();
697                         // Actually the Finder, but that's OK
698
return browser;
699                      }
700                   }
701                }
702                catch( IllegalArgumentException JavaDoc iare )
703                {
704                   browser = browser;
705                   errorMessage = iare.getMessage();
706                   return null;
707                }
708                catch( IllegalAccessException JavaDoc iae )
709                {
710                   browser = null;
711                   errorMessage = iae.getMessage();
712                   return browser;
713                }
714                catch( InvocationTargetException JavaDoc ite )
715                {
716                   browser = null;
717                   errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
718                   return browser;
719                }
720             }
721             browser = null;
722             break;
723          case MRJ_3_0:
724          case MRJ_3_1:
725             browser = "";
726             // Return something non-null
727
break;
728          case WINDOWS_NT:
729             browser = "cmd.exe";
730             break;
731          case WINDOWS_9x:
732             browser = "command.com";
733             break;
734          case OTHER:
735          default:
736             browser = "netscape";
737             break;
738       }
739       return browser;
740    }
741
742    static
743    {
744       loadedWithoutErrors = true;
745       String JavaDoc osName = System.getProperty( "os.name" );
746       if( osName.startsWith( "Mac OS" ) )
747       {
748          String JavaDoc mrjVersion = System.getProperty( "mrj.version" );
749          String JavaDoc majorMRJVersion = mrjVersion.substring( 0, 3 );
750          try
751          {
752             double version = Double.valueOf( majorMRJVersion ).doubleValue();
753             if( version == 2 )
754             {
755                jvm = MRJ_2_0;
756             }
757             else if( version >= 2.1 && version < 3 )
758             {
759                // Assume that all 2.x versions of MRJ work the same. MRJ 2.1 actually
760
// works via Runtime.exec() and 2.2 supports that but has an openURL() method
761
// as well that we currently ignore.
762
jvm = MRJ_2_1;
763             }
764             else if( version == 3.0 )
765             {
766                jvm = MRJ_3_0;
767             }
768             else if( version >= 3.1 )
769             {
770                // Assume that all 3.1 and later versions of MRJ work the same.
771
jvm = MRJ_3_1;
772             }
773             else
774             {
775                loadedWithoutErrors = false;
776                errorMessage = "Unsupported MRJ version: " + version;
777             }
778          }
779          catch( NumberFormatException JavaDoc nfe )
780          {
781             loadedWithoutErrors = false;
782             errorMessage = "Invalid MRJ version: " + mrjVersion;
783          }
784       }
785       else if( osName.startsWith( "Windows" ) )
786       {
787          if( osName.indexOf( "9" ) != -1 )
788          {
789             jvm = WINDOWS_9x;
790          }
791          else
792          {
793             jvm = WINDOWS_NT;
794          }
795       }
796       else
797       {
798          jvm = OTHER;
799       }
800
801       if( loadedWithoutErrors )
802       {
803          // if we haven't hit any errors yet
804
loadedWithoutErrors = loadClasses();
805       }
806    }
807 }
808
Popular Tags