1 package uk.ac.roe.antigen.utils; 2 3 import java.io.File ; 4 import java.io.FileNotFoundException ; 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 55 public class BrowserLauncher { 56 57 60 private static int jvm; 61 62 63 private static Object browser; 64 65 72 private static boolean loadedWithoutErrors; 73 74 75 private static Class mrjFileUtilsClass; 76 77 78 private static Class mrjOSTypeClass; 79 80 81 private static Class aeDescClass; 82 83 84 private static Constructor aeTargetConstructor; 85 86 87 private static Constructor appleEventConstructor; 88 89 90 private static Constructor aeDescConstructor; 91 92 93 private static Method findFolder; 94 95 96 private static Method getFileCreator; 97 98 99 private static Method getFileType; 100 101 102 private static Method openURL; 103 104 105 private static Method makeOSType; 106 107 108 private static Method putParameter; 109 110 111 private static Method sendNoReply; 112 113 114 private static Object kSystemFolderType; 115 116 117 private static Integer keyDirectObject; 118 119 120 private static Integer kAutoGenerateReturnID; 121 122 123 private static Integer kAnyTransactionID; 124 125 126 private static Object linkage; 127 128 129 private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox"; 130 131 132 private static final int MRJ_2_0 = 0; 133 134 135 private static final int MRJ_2_1 = 1; 136 137 138 private static final int MRJ_3_0 = 3; 139 140 141 private static final int MRJ_3_1 = 4; 142 143 144 private static final int WINDOWS_NT = 5; 145 146 147 private static final int WINDOWS_9x = 6; 148 149 150 private static final int OTHER = -1; 151 152 156 private static final String FINDER_TYPE = "FNDR"; 157 158 162 private static final String FINDER_CREATOR = "MACS"; 163 164 165 private static final String GURL_EVENT = "GURL"; 166 167 171 private static final String FIRST_WINDOWS_PARAMETER = "/c"; 172 173 174 private static final String SECOND_WINDOWS_PARAMETER = "start"; 175 176 181 private static final String THIRD_WINDOWS_PARAMETER = "\"\""; 182 183 187 private static final String NETSCAPE_REMOTE_PARAMETER = "-remote"; 188 private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL("; 189 private static final String NETSCAPE_OPEN_PARAMETER_END = ")'"; 190 191 194 private static String errorMessage; 195 196 200 static { 201 loadedWithoutErrors = true; 202 String osName = System.getProperty("os.name"); 203 if (osName.startsWith("Mac OS")) { 204 String mrjVersion = System.getProperty("mrj.version"); 205 String majorMRJVersion = mrjVersion.substring(0, 3); 206 try { 207 double version = Double.valueOf(majorMRJVersion).doubleValue(); 208 if (version == 2) { 209 jvm = MRJ_2_0; 210 } else if (version >= 2.1 && version < 3) { 211 jvm = MRJ_2_1; 215 } else if (version == 3.0) { 216 jvm = MRJ_3_0; 217 } else if (version >= 3.1) { 218 jvm = MRJ_3_1; 220 } else { 221 loadedWithoutErrors = false; 222 errorMessage = "Unsupported MRJ version: " + version; 223 } 224 } catch (NumberFormatException nfe) { 225 loadedWithoutErrors = false; 226 errorMessage = "Invalid MRJ version: " + mrjVersion; 227 } 228 } else if (osName.startsWith("Windows")) { 229 if (osName.indexOf("9") != -1) { 230 jvm = WINDOWS_9x; 231 } else { 232 jvm = WINDOWS_NT; 233 } 234 } else { 235 jvm = OTHER; 236 } 237 238 if (loadedWithoutErrors) { loadedWithoutErrors = loadClasses(); 240 } 241 } 242 243 246 private BrowserLauncher() { } 247 248 254 private static boolean loadClasses() { 255 switch (jvm) { 256 case MRJ_2_0: 257 try { 258 Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget"); 259 Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils"); 260 Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent"); 261 Class aeClass = Class.forName("com.apple.MacOS.ae"); 262 aeDescClass = Class.forName("com.apple.MacOS.AEDesc"); 263 264 aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class [] { int.class }); 265 appleEventConstructor = appleEventClass.getDeclaredConstructor(new Class [] { int.class, int.class, aeTargetClass, int.class, int.class }); 266 aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class [] { String .class }); 267 268 makeOSType = osUtilsClass.getDeclaredMethod("makeOSType", new Class [] { String .class }); 269 putParameter = appleEventClass.getDeclaredMethod("putParameter", new Class [] { int.class, aeDescClass }); 270 sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply", new Class [] { }); 271 272 Field keyDirectObjectField = aeClass.getDeclaredField("keyDirectObject"); 273 keyDirectObject = (Integer ) keyDirectObjectField.get(null); 274 Field autoGenerateReturnIDField = appleEventClass.getDeclaredField("kAutoGenerateReturnID"); 275 kAutoGenerateReturnID = (Integer ) autoGenerateReturnIDField.get(null); 276 Field anyTransactionIDField = appleEventClass.getDeclaredField("kAnyTransactionID"); 277 kAnyTransactionID = (Integer ) anyTransactionIDField.get(null); 278 } catch (ClassNotFoundException cnfe) { 279 errorMessage = cnfe.getMessage(); 280 return false; 281 } catch (NoSuchMethodException nsme) { 282 errorMessage = nsme.getMessage(); 283 return false; 284 } catch (NoSuchFieldException nsfe) { 285 errorMessage = nsfe.getMessage(); 286 return false; 287 } catch (IllegalAccessException iae) { 288 errorMessage = iae.getMessage(); 289 return false; 290 } 291 break; 292 case MRJ_2_1: 293 try { 294 mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils"); 295 mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType"); 296 Field systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType"); 297 kSystemFolderType = systemFolderField.get(null); 298 findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class [] { mrjOSTypeClass }); 299 getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class [] { File .class }); 300 getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class [] { File .class }); 301 } catch (ClassNotFoundException cnfe) { 302 errorMessage = cnfe.getMessage(); 303 return false; 304 } catch (NoSuchFieldException nsfe) { 305 errorMessage = nsfe.getMessage(); 306 return false; 307 } catch (NoSuchMethodException nsme) { 308 errorMessage = nsme.getMessage(); 309 return false; 310 } catch (SecurityException se) { 311 errorMessage = se.getMessage(); 312 return false; 313 } catch (IllegalAccessException iae) { 314 errorMessage = iae.getMessage(); 315 return false; 316 } 317 break; 318 case MRJ_3_0: 319 try { 320 Class linker = Class.forName("com.apple.mrj.jdirect.Linker"); 321 Constructor constructor = linker.getConstructor(new Class []{ Class .class }); 322 linkage = constructor.newInstance(new Object [] { BrowserLauncher.class }); 323 } catch (ClassNotFoundException cnfe) { 324 errorMessage = cnfe.getMessage(); 325 return false; 326 } catch (NoSuchMethodException nsme) { 327 errorMessage = nsme.getMessage(); 328 return false; 329 } catch (InvocationTargetException ite) { 330 errorMessage = ite.getMessage(); 331 return false; 332 } catch (InstantiationException ie) { 333 errorMessage = ie.getMessage(); 334 return false; 335 } catch (IllegalAccessException iae) { 336 errorMessage = iae.getMessage(); 337 return false; 338 } 339 break; 340 case MRJ_3_1: 341 try { 342 mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils"); 343 openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class [] { String .class }); 344 } catch (ClassNotFoundException cnfe) { 345 errorMessage = cnfe.getMessage(); 346 return false; 347 } catch (NoSuchMethodException nsme) { 348 errorMessage = nsme.getMessage(); 349 return false; 350 } 351 break; 352 default: 353 break; 354 } 355 return true; 356 } 357 358 366 private static Object locateBrowser() { 367 if (browser != null) { 368 return browser; 369 } 370 switch (jvm) { 371 case MRJ_2_0: 372 try { 373 Integer finderCreatorCode = (Integer ) makeOSType.invoke(null, new Object [] { FINDER_CREATOR }); 374 Object aeTarget = aeTargetConstructor.newInstance(new Object [] { finderCreatorCode }); 375 Integer gurlType = (Integer ) makeOSType.invoke(null, new Object [] { GURL_EVENT }); 376 Object appleEvent = appleEventConstructor.newInstance(new Object [] { gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID }); 377 return appleEvent; 383 } catch (IllegalAccessException iae) { 384 browser = null; 385 errorMessage = iae.getMessage(); 386 return browser; 387 } catch (InstantiationException ie) { 388 browser = null; 389 errorMessage = ie.getMessage(); 390 return browser; 391 } catch (InvocationTargetException ite) { 392 browser = null; 393 errorMessage = ite.getMessage(); 394 return browser; 395 } 396 case MRJ_2_1: 397 File systemFolder; 398 try { 399 systemFolder = (File ) findFolder.invoke(null, new Object [] { kSystemFolderType }); 400 } catch (IllegalArgumentException iare) { 401 browser = null; 402 errorMessage = iare.getMessage(); 403 return browser; 404 } catch (IllegalAccessException iae) { 405 browser = null; 406 errorMessage = iae.getMessage(); 407 return browser; 408 } catch (InvocationTargetException ite) { 409 browser = null; 410 errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage(); 411 return browser; 412 } 413 String [] systemFolderFiles = systemFolder.list(); 414 for(int i = 0; i < systemFolderFiles.length; i++) { 416 try { 417 File file = new File (systemFolder, systemFolderFiles[i]); 418 if (!file.isFile()) { 419 continue; 420 } 421 Object fileType = getFileType.invoke(null, new Object [] { file }); 427 if (FINDER_TYPE.equals(fileType.toString())) { 428 Object fileCreator = getFileCreator.invoke(null, new Object [] { file }); 429 if (FINDER_CREATOR.equals(fileCreator.toString())) { 430 browser = file.toString(); return browser; 432 } 433 } 434 } catch (IllegalArgumentException iare) { 435 browser = browser; 436 errorMessage = iare.getMessage(); 437 return null; 438 } catch (IllegalAccessException iae) { 439 browser = null; 440 errorMessage = iae.getMessage(); 441 return browser; 442 } catch (InvocationTargetException ite) { 443 browser = null; 444 errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage(); 445 return browser; 446 } 447 } 448 browser = null; 449 break; 450 case MRJ_3_0: 451 case MRJ_3_1: 452 browser = ""; break; 454 case WINDOWS_NT: 455 browser = "cmd.exe"; 456 break; 457 case WINDOWS_9x: 458 browser = "command.com"; 459 break; 460 case OTHER: 461 default: 462 browser = "netscape"; 463 break; 464 } 465 return browser; 466 } 467 468 473 public static void openURL(String url) throws IOException { 474 if (!loadedWithoutErrors) { 475 throw new IOException ("Exception in finding browser: " + errorMessage); 476 } 477 Object browser = locateBrowser(); 478 if (browser == null) { 479 throw new IOException ("Unable to locate browser: " + errorMessage); 480 } 481 482 switch (jvm) { 483 case MRJ_2_0: 484 Object aeDesc = null; 485 try { 486 aeDesc = aeDescConstructor.newInstance(new Object [] { url }); 487 putParameter.invoke(browser, new Object [] { keyDirectObject, aeDesc }); 488 sendNoReply.invoke(browser, new Object [] { }); 489 } catch (InvocationTargetException ite) { 490 throw new IOException ("InvocationTargetException while creating AEDesc: " + ite.getMessage()); 491 } catch (IllegalAccessException iae) { 492 throw new IOException ("IllegalAccessException while building AppleEvent: " + iae.getMessage()); 493 } catch (InstantiationException ie) { 494 throw new IOException ("InstantiationException while creating AEDesc: " + ie.getMessage()); 495 } finally { 496 aeDesc = null; browser = null; } 499 break; 500 case MRJ_2_1: 501 Runtime.getRuntime().exec(new String [] { (String ) browser, url } ); 502 break; 503 case MRJ_3_0: 504 int[] instance = new int[1]; 505 int result = ICStart(instance, 0); 506 if (result == 0) { 507 int[] selectionStart = new int[] { 0 }; 508 byte[] urlBytes = url.getBytes(); 509 int[] selectionEnd = new int[] { urlBytes.length }; 510 result = ICLaunchURL(instance[0], new byte[] { 0 }, urlBytes, 511 urlBytes.length, selectionStart, 512 selectionEnd); 513 if (result == 0) { 514 ICStop(instance); 517 } else { 518 throw new IOException ("Unable to launch URL: " + result); 519 } 520 } else { 521 throw new IOException ("Unable to create an Internet Config instance: " + result); 522 } 523 break; 524 case MRJ_3_1: 525 try { 526 openURL.invoke(null, new Object [] { url }); 527 } catch (InvocationTargetException ite) { 528 throw new IOException ("InvocationTargetException while calling openURL: " + ite.getMessage()); 529 } catch (IllegalAccessException iae) { 530 throw new IOException ("IllegalAccessException while calling openURL: " + iae.getMessage()); 531 } 532 break; 533 case WINDOWS_NT: 534 case WINDOWS_9x: 535 Process process = Runtime.getRuntime().exec(new String [] { (String ) browser, 538 FIRST_WINDOWS_PARAMETER, 539 SECOND_WINDOWS_PARAMETER, 540 THIRD_WINDOWS_PARAMETER, 541 '"' + url + '"' }); 542 try { 545 process.waitFor(); 546 process.exitValue(); 547 } catch (InterruptedException ie) { 548 throw new IOException ("InterruptedException while launching browser: " + ie.getMessage()); 549 } 550 break; 551 case OTHER: 552 554 process = Runtime.getRuntime().exec(new String [] { (String ) browser, 556 NETSCAPE_REMOTE_PARAMETER, 557 NETSCAPE_OPEN_PARAMETER_START + 558 url + 559 NETSCAPE_OPEN_PARAMETER_END }); 560 try { 561 int exitCode = process.waitFor(); 562 if (exitCode != 0) { Runtime.getRuntime().exec(new String [] { (String ) browser, url }); 564 } 565 } catch (InterruptedException ie) { 566 throw new IOException ("InterruptedException while launching browser: " + ie.getMessage()); 567 } 568 break; 569 default: 570 Runtime.getRuntime().exec(new String [] { (String ) browser, url }); 572 break; 573 } 574 } 575 576 580 private native static int ICStart(int[] instance, int signature); 581 private native static int ICStop(int[] instance); 582 private native static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len, 583 int[] selectionStart, int[] selectionEnd); 584 } 585 | Popular Tags |