00001 package edu.virtualschool.jwaa.swing;
00002
00003 import java.io.File;
00004 import java.io.IOException;
00005 import java.lang.reflect.Constructor;
00006 import java.lang.reflect.Field;
00007 import java.lang.reflect.InvocationTargetException;
00008 import java.lang.reflect.Method;
00009
00054 public class BrowserLauncher
00055 {
00056
00060 private static int jvm;
00061
00063 private static Object browser;
00064
00072 private static boolean loadedWithoutErrors;
00073
00075 private static Class mrjFileUtilsClass;
00076
00078 private static Class mrjOSTypeClass;
00079
00081 private static Class aeDescClass;
00082
00084 private static Constructor aeTargetConstructor;
00085
00087 private static Constructor appleEventConstructor;
00088
00090 private static Constructor aeDescConstructor;
00091
00093 private static Method findFolder;
00094
00096 private static Method getFileCreator;
00097
00099 private static Method getFileType;
00100
00102 private static Method openURL;
00103
00105 private static Method makeOSType;
00106
00108 private static Method putParameter;
00109
00111 private static Method sendNoReply;
00112
00114 private static Object kSystemFolderType;
00115
00117 private static Integer keyDirectObject;
00118
00120 private static Integer kAutoGenerateReturnID;
00121
00123 private static Integer kAnyTransactionID;
00124
00126 private static Object linkage;
00127
00129
00130
00132 private static final int MRJ_2_0 = 0;
00133
00135 private static final int MRJ_2_1 = 1;
00136
00138 private static final int MRJ_3_0 = 3;
00139
00141 private static final int MRJ_3_1 = 4;
00142
00144 private static final int WINDOWS_NT = 5;
00145
00147 private static final int WINDOWS_9x = 6;
00148
00150 private static final int OTHER = -1;
00151
00156 private static final String FINDER_TYPE = "FNDR";
00157
00162 private static final String FINDER_CREATOR = "MACS";
00163
00165 private static final String GURL_EVENT = "GURL";
00166
00171 private static final String FIRST_WINDOWS_PARAMETER = "/c";
00172
00174 private static final String SECOND_WINDOWS_PARAMETER = "start";
00175
00181 private static final String THIRD_WINDOWS_PARAMETER = "\"\"";
00182
00187 private static final String NETSCAPE_REMOTE_PARAMETER = "-remote";
00188 private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
00189 private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
00190
00194 private static String errorMessage;
00195
00200 static {
00201 loadedWithoutErrors = true;
00202 String osName = System.getProperty("os.name");
00203 if (osName.startsWith("Mac OS")) {
00204 String mrjVersion = System.getProperty("mrj.version");
00205 String majorMRJVersion = mrjVersion.substring(0, 3);
00206 try {
00207 double version = Double.valueOf(majorMRJVersion).doubleValue();
00208 if (version == 2) {
00209 jvm = MRJ_2_0;
00210 } else if (version >= 2.1 && version < 3) {
00211
00212
00213
00214 jvm = MRJ_2_1;
00215 } else if (version == 3.0) {
00216 jvm = MRJ_3_0;
00217 } else if (version >= 3.1) {
00218
00219 jvm = MRJ_3_1;
00220 } else {
00221 loadedWithoutErrors = false;
00222 errorMessage = "Unsupported MRJ version: " + version;
00223 }
00224 } catch (NumberFormatException nfe) {
00225 loadedWithoutErrors = false;
00226 errorMessage = "Invalid MRJ version: " + mrjVersion;
00227 }
00228 } else if (osName.startsWith("Windows")) {
00229 if (osName.indexOf("9") != -1) {
00230 jvm = WINDOWS_9x;
00231 } else {
00232 jvm = WINDOWS_NT;
00233 }
00234 } else {
00235 jvm = OTHER;
00236 }
00237
00238 if (loadedWithoutErrors) {
00239 loadedWithoutErrors = loadClasses();
00240 }
00241 }
00242
00246 private BrowserLauncher() { }
00247
00254 private static boolean loadClasses() {
00255 switch (jvm) {
00256 case MRJ_2_0:
00257 try {
00258 Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
00259 Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
00260 Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent");
00261 Class aeClass = Class.forName("com.apple.MacOS.ae");
00262 aeDescClass = Class.forName("com.apple.MacOS.AEDesc");
00263
00264 aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class [] { int.class });
00265 appleEventConstructor = appleEventClass.getDeclaredConstructor(new Class[] { int.class, int.class, aeTargetClass, int.class, int.class });
00266 aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class[] { String.class });
00267
00268 makeOSType = osUtilsClass.getDeclaredMethod("makeOSType", new Class [] { String.class });
00269 putParameter = appleEventClass.getDeclaredMethod("putParameter", new Class[] { int.class, aeDescClass });
00270 sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply", new Class[] { });
00271
00272 Field keyDirectObjectField = aeClass.getDeclaredField("keyDirectObject");
00273 keyDirectObject = (Integer) keyDirectObjectField.get(null);
00274 Field autoGenerateReturnIDField = appleEventClass.getDeclaredField("kAutoGenerateReturnID");
00275 kAutoGenerateReturnID = (Integer) autoGenerateReturnIDField.get(null);
00276 Field anyTransactionIDField = appleEventClass.getDeclaredField("kAnyTransactionID");
00277 kAnyTransactionID = (Integer) anyTransactionIDField.get(null);
00278 } catch (ClassNotFoundException cnfe) {
00279 errorMessage = cnfe.getMessage();
00280 return false;
00281 } catch (NoSuchMethodException nsme) {
00282 errorMessage = nsme.getMessage();
00283 return false;
00284 } catch (NoSuchFieldException nsfe) {
00285 errorMessage = nsfe.getMessage();
00286 return false;
00287 } catch (IllegalAccessException iae) {
00288 errorMessage = iae.getMessage();
00289 return false;
00290 }
00291 break;
00292 case MRJ_2_1:
00293 try {
00294 mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
00295 mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType");
00296 Field systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType");
00297 kSystemFolderType = systemFolderField.get(null);
00298 findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class[] { mrjOSTypeClass });
00299 getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class[] { File.class });
00300 getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class[] { File.class });
00301 } catch (ClassNotFoundException cnfe) {
00302 errorMessage = cnfe.getMessage();
00303 return false;
00304 } catch (NoSuchFieldException nsfe) {
00305 errorMessage = nsfe.getMessage();
00306 return false;
00307 } catch (NoSuchMethodException nsme) {
00308 errorMessage = nsme.getMessage();
00309 return false;
00310 } catch (SecurityException se) {
00311 errorMessage = se.getMessage();
00312 return false;
00313 } catch (IllegalAccessException iae) {
00314 errorMessage = iae.getMessage();
00315 return false;
00316 }
00317 break;
00318 case MRJ_3_0:
00319 try {
00320 Class linker = Class.forName("com.apple.mrj.jdirect.Linker");
00321 Constructor constructor = linker.getConstructor(new Class[]{ Class.class });
00322 linkage = constructor.newInstance(new Object[] { BrowserLauncher.class });
00323 } catch (ClassNotFoundException cnfe) {
00324 errorMessage = cnfe.getMessage();
00325 return false;
00326 } catch (NoSuchMethodException nsme) {
00327 errorMessage = nsme.getMessage();
00328 return false;
00329 } catch (InvocationTargetException ite) {
00330 errorMessage = ite.getMessage();
00331 return false;
00332 } catch (InstantiationException ie) {
00333 errorMessage = ie.getMessage();
00334 return false;
00335 } catch (IllegalAccessException iae) {
00336 errorMessage = iae.getMessage();
00337 return false;
00338 }
00339 break;
00340 case MRJ_3_1:
00341 try {
00342 mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
00343 openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class[] { String.class });
00344 } catch (ClassNotFoundException cnfe) {
00345 errorMessage = cnfe.getMessage();
00346 return false;
00347 } catch (NoSuchMethodException nsme) {
00348 errorMessage = nsme.getMessage();
00349 return false;
00350 }
00351 break;
00352 default:
00353 break;
00354 }
00355 return true;
00356 }
00357
00366 private static Object locateBrowser() {
00367 if (browser != null) {
00368 return browser;
00369 }
00370 switch (jvm) {
00371 case MRJ_2_0:
00372 try {
00373 Integer finderCreatorCode = (Integer) makeOSType.invoke(null, new Object[] { FINDER_CREATOR });
00374 Object aeTarget = aeTargetConstructor.newInstance(new Object[] { finderCreatorCode });
00375 Integer gurlType = (Integer) makeOSType.invoke(null, new Object[] { GURL_EVENT });
00376 Object appleEvent = appleEventConstructor.newInstance(new Object[] { gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID });
00377
00378
00379
00380
00381
00382 return appleEvent;
00383 } catch (IllegalAccessException iae) {
00384 browser = null;
00385 errorMessage = iae.getMessage();
00386 return browser;
00387 } catch (InstantiationException ie) {
00388 browser = null;
00389 errorMessage = ie.getMessage();
00390 return browser;
00391 } catch (InvocationTargetException ite) {
00392 browser = null;
00393 errorMessage = ite.getMessage();
00394 return browser;
00395 }
00396 case MRJ_2_1:
00397 File systemFolder;
00398 try {
00399 systemFolder = (File) findFolder.invoke(null, new Object[] { kSystemFolderType });
00400 } catch (IllegalArgumentException iare) {
00401 browser = null;
00402 errorMessage = iare.getMessage();
00403 return browser;
00404 } catch (IllegalAccessException iae) {
00405 browser = null;
00406 errorMessage = iae.getMessage();
00407 return browser;
00408 } catch (InvocationTargetException ite) {
00409 browser = null;
00410 errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
00411 return browser;
00412 }
00413 String[] systemFolderFiles = systemFolder.list();
00414
00415 for(int i = 0; i < systemFolderFiles.length; i++) {
00416 try {
00417 File file = new File(systemFolder, systemFolderFiles[i]);
00418 if (!file.isFile()) {
00419 continue;
00420 }
00421
00422
00423
00424
00425
00426 Object fileType = getFileType.invoke(null, new Object[] { file });
00427 if (FINDER_TYPE.equals(fileType.toString())) {
00428 Object fileCreator = getFileCreator.invoke(null, new Object[] { file });
00429 if (FINDER_CREATOR.equals(fileCreator.toString())) {
00430 browser = file.toString();
00431 return browser;
00432 }
00433 }
00434 } catch (IllegalArgumentException iare) {
00435 errorMessage = iare.getMessage();
00436 return null;
00437 } catch (IllegalAccessException iae) {
00438 browser = null;
00439 errorMessage = iae.getMessage();
00440 return browser;
00441 } catch (InvocationTargetException ite) {
00442 browser = null;
00443 errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
00444 return browser;
00445 }
00446 }
00447 browser = null;
00448 break;
00449 case MRJ_3_0:
00450 case MRJ_3_1:
00451 browser = "";
00452 break;
00453 case WINDOWS_NT:
00454 browser = "cmd.exe";
00455 break;
00456 case WINDOWS_9x:
00457 browser = "command.com";
00458 break;
00459 case OTHER:
00460 default:
00461 browser = "netscape";
00462 break;
00463 }
00464 return browser;
00465 }
00466
00472 public static void openURL(String url) throws IOException {
00473 if (!loadedWithoutErrors) {
00474 throw new IOException("Exception in finding browser: " + errorMessage);
00475 }
00476 Object browser = locateBrowser();
00477 if (browser == null) {
00478 throw new IOException("Unable to locate browser: " + errorMessage);
00479 }
00480
00481 switch (jvm) {
00482 case MRJ_2_0:
00483 Object aeDesc = null;
00484 try {
00485 aeDesc = aeDescConstructor.newInstance(new Object[] { url });
00486 putParameter.invoke(browser, new Object[] { keyDirectObject, aeDesc });
00487 sendNoReply.invoke(browser, new Object[] { });
00488 } catch (InvocationTargetException ite) {
00489 throw new IOException("InvocationTargetException while creating AEDesc: " + ite.getMessage());
00490 } catch (IllegalAccessException iae) {
00491 throw new IOException("IllegalAccessException while building AppleEvent: " + iae.getMessage());
00492 } catch (InstantiationException ie) {
00493 throw new IOException("InstantiationException while creating AEDesc: " + ie.getMessage());
00494 } finally {
00495 aeDesc = null;
00496 browser = null;
00497 }
00498 break;
00499 case MRJ_2_1:
00500 Runtime.getRuntime().exec(new String[] { (String) browser, url } );
00501 break;
00502 case MRJ_3_0:
00503 int[] instance = new int[1];
00504 int result = ICStart(instance, 0);
00505 if (result == 0) {
00506 int[] selectionStart = new int[] { 0 };
00507 byte[] urlBytes = url.getBytes();
00508 int[] selectionEnd = new int[] { urlBytes.length };
00509 result = ICLaunchURL(instance[0], new byte[] { 0 }, urlBytes,
00510 urlBytes.length, selectionStart,
00511 selectionEnd);
00512 if (result == 0) {
00513
00514
00515 ICStop(instance);
00516 } else {
00517 throw new IOException("Unable to launch URL: " + result);
00518 }
00519 } else {
00520 throw new IOException("Unable to create an Internet Config instance: " + result);
00521 }
00522 break;
00523 case MRJ_3_1:
00524 try {
00525 openURL.invoke(null, new Object[] { url });
00526 } catch (InvocationTargetException ite) {
00527 throw new IOException("InvocationTargetException while calling openURL: " + ite.getMessage());
00528 } catch (IllegalAccessException iae) {
00529 throw new IOException("IllegalAccessException while calling openURL: " + iae.getMessage());
00530 }
00531 break;
00532 case WINDOWS_NT:
00533 case WINDOWS_9x:
00534
00535
00536 Process process = Runtime.getRuntime().exec(new String[] { (String) browser,
00537 FIRST_WINDOWS_PARAMETER,
00538 SECOND_WINDOWS_PARAMETER,
00539 THIRD_WINDOWS_PARAMETER,
00540 '"' + url + '"' });
00541
00542
00543 try {
00544 process.waitFor();
00545 process.exitValue();
00546 } catch (InterruptedException ie) {
00547 throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
00548 }
00549 break;
00550 case OTHER:
00551
00552
00553
00554 process = Runtime.getRuntime().exec(new String[] { (String) browser,
00555 NETSCAPE_REMOTE_PARAMETER,
00556 NETSCAPE_OPEN_PARAMETER_START +
00557 url +
00558 NETSCAPE_OPEN_PARAMETER_END });
00559 try {
00560 int exitCode = process.waitFor();
00561 if (exitCode != 0) {
00562 Runtime.getRuntime().exec(new String[] { (String) browser, url });
00563 }
00564 } catch (InterruptedException ie) {
00565 throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
00566 }
00567 break;
00568 default:
00569
00570 Runtime.getRuntime().exec(new String[] { (String) browser, url });
00571 break;
00572 }
00573 }
00574
00579 private native static int ICStart(int[] instance, int signature);
00580 private native static int ICStop(int[] instance);
00581 private native static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len,
00582 int[] selectionStart, int[] selectionEnd);
00583 }