1 11 12 package org.jivesoftware.messenger.launcher; 13 14 import java.io.File ; 15 import java.io.IOException ; 16 import java.lang.reflect.Constructor ; 17 import java.lang.reflect.Field ; 18 import java.lang.reflect.InvocationTargetException ; 19 import java.lang.reflect.Method ; 20 21 65 public class BrowserLauncher { 66 67 71 private static int jvm; 72 73 76 private static Object browser; 77 78 85 private static boolean loadedWithoutErrors; 86 87 90 private static Class mrjFileUtilsClass; 91 92 95 private static Class mrjOSTypeClass; 96 97 100 private static Class aeDescClass; 101 102 105 private static Constructor aeTargetConstructor; 106 107 110 private static Constructor appleEventConstructor; 111 112 115 private static Constructor aeDescConstructor; 116 117 120 private static Method findFolder; 121 122 125 private static Method getFileCreator; 126 127 130 private static Method getFileType; 131 132 135 private static Method openURL; 136 137 140 private static Method makeOSType; 141 142 145 private static Method putParameter; 146 147 150 private static Method sendNoReply; 151 152 155 private static Object kSystemFolderType; 156 157 160 private static Integer keyDirectObject; 161 162 165 private static Integer kAutoGenerateReturnID; 166 167 170 private static Integer kAnyTransactionID; 171 172 175 private static Object linkage; 176 177 180 private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox"; 181 182 185 private static final int MRJ_2_0 = 0; 186 187 190 private static final int MRJ_2_1 = 1; 191 192 195 private static final int MRJ_3_0 = 3; 196 197 200 private static final int MRJ_3_1 = 4; 201 202 205 private static final int WINDOWS_NT = 5; 206 207 210 private static final int WINDOWS_9x = 6; 211 212 215 private static final int OTHER = -1; 216 217 221 private static final String FINDER_TYPE = "FNDR"; 222 223 227 private static final String FINDER_CREATOR = "MACS"; 228 229 232 private static final String GURL_EVENT = "GURL"; 233 234 238 private static final String FIRST_WINDOWS_PARAMETER = "/c"; 239 240 243 private static final String SECOND_WINDOWS_PARAMETER = "start"; 244 245 250 private static final String THIRD_WINDOWS_PARAMETER = "\"\""; 251 252 256 private static final String NETSCAPE_REMOTE_PARAMETER = "-remote"; 257 private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL("; 258 private static final String NETSCAPE_OPEN_PARAMETER_END = ")'"; 259 260 263 private static String errorMessage; 264 265 269 static { 270 loadedWithoutErrors = true; 271 String osName = System.getProperty("os.name"); 272 if (osName.startsWith("Mac OS")) { 273 String mrjVersion = System.getProperty("mrj.version"); 274 String majorMRJVersion = mrjVersion.substring(0, 3); 275 try { 276 double version = Double.valueOf(majorMRJVersion).doubleValue(); 277 if (version == 2) { 278 jvm = MRJ_2_0; 279 } 280 else if (version >= 2.1 && version < 3) { 281 jvm = MRJ_2_1; 285 } 286 else if (version == 3.0) { 287 jvm = MRJ_3_0; 288 } 289 else if (version >= 3.1) { 290 jvm = MRJ_3_1; 292 } 293 else { 294 loadedWithoutErrors = false; 295 errorMessage = "Unsupported MRJ version: " + version; 296 } 297 } 298 catch (NumberFormatException nfe) { 299 loadedWithoutErrors = false; 300 errorMessage = "Invalid MRJ version: " + mrjVersion; 301 } 302 } 303 else if (osName.startsWith("Windows")) { 304 if (osName.indexOf("9") != -1) { 305 jvm = WINDOWS_9x; 306 } 307 else { 308 jvm = WINDOWS_NT; 309 } 310 } 311 else { 312 jvm = OTHER; 313 } 314 315 if (loadedWithoutErrors) { loadedWithoutErrors = loadClasses(); 317 } 318 } 319 320 323 private BrowserLauncher() { 324 } 325 326 333 private static boolean loadClasses() { 334 switch (jvm) { 335 case MRJ_2_0: 336 try { 337 Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget"); 338 Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils"); 339 Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent"); 340 Class aeClass = Class.forName("com.apple.MacOS.ae"); 341 aeDescClass = Class.forName("com.apple.MacOS.AEDesc"); 342 343 aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class []{int.class}); 344 appleEventConstructor = appleEventClass.getDeclaredConstructor(new Class []{int.class, int.class, aeTargetClass, int.class, int.class}); 345 aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class []{String .class}); 346 347 makeOSType = osUtilsClass.getDeclaredMethod("makeOSType", new Class []{String .class}); 348 putParameter = appleEventClass.getDeclaredMethod("putParameter", new Class []{int.class, aeDescClass}); 349 sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply", new Class []{}); 350 351 Field keyDirectObjectField = aeClass.getDeclaredField("keyDirectObject"); 352 keyDirectObject = (Integer )keyDirectObjectField.get(null); 353 Field autoGenerateReturnIDField = appleEventClass.getDeclaredField("kAutoGenerateReturnID"); 354 kAutoGenerateReturnID = (Integer )autoGenerateReturnIDField.get(null); 355 Field anyTransactionIDField = appleEventClass.getDeclaredField("kAnyTransactionID"); 356 kAnyTransactionID = (Integer )anyTransactionIDField.get(null); 357 } 358 catch (ClassNotFoundException cnfe) { 359 errorMessage = cnfe.getMessage(); 360 return false; 361 } 362 catch (NoSuchMethodException nsme) { 363 errorMessage = nsme.getMessage(); 364 return false; 365 } 366 catch (NoSuchFieldException nsfe) { 367 errorMessage = nsfe.getMessage(); 368 return false; 369 } 370 catch (IllegalAccessException iae) { 371 errorMessage = iae.getMessage(); 372 return false; 373 } 374 break; 375 case MRJ_2_1: 376 try { 377 mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils"); 378 mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType"); 379 Field systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType"); 380 kSystemFolderType = systemFolderField.get(null); 381 findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class []{mrjOSTypeClass}); 382 getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class []{File .class}); 383 getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class []{File .class}); 384 } 385 catch (ClassNotFoundException cnfe) { 386 errorMessage = cnfe.getMessage(); 387 return false; 388 } 389 catch (NoSuchFieldException nsfe) { 390 errorMessage = nsfe.getMessage(); 391 return false; 392 } 393 catch (NoSuchMethodException nsme) { 394 errorMessage = nsme.getMessage(); 395 return false; 396 } 397 catch (SecurityException se) { 398 errorMessage = se.getMessage(); 399 return false; 400 } 401 catch (IllegalAccessException iae) { 402 errorMessage = iae.getMessage(); 403 return false; 404 } 405 break; 406 case MRJ_3_0: 407 try { 408 Class linker = Class.forName("com.apple.mrj.jdirect.Linker"); 409 Constructor constructor = linker.getConstructor(new Class []{Class .class}); 410 linkage = constructor.newInstance(new Object []{BrowserLauncher.class}); 411 } 412 catch (ClassNotFoundException cnfe) { 413 errorMessage = cnfe.getMessage(); 414 return false; 415 } 416 catch (NoSuchMethodException nsme) { 417 errorMessage = nsme.getMessage(); 418 return false; 419 } 420 catch (InvocationTargetException ite) { 421 errorMessage = ite.getMessage(); 422 return false; 423 } 424 catch (InstantiationException ie) { 425 errorMessage = ie.getMessage(); 426 return false; 427 } 428 catch (IllegalAccessException iae) { 429 errorMessage = iae.getMessage(); 430 return false; 431 } 432 break; 433 case MRJ_3_1: 434 try { 435 mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils"); 436 openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class []{String .class}); 437 } 438 catch (ClassNotFoundException cnfe) { 439 errorMessage = cnfe.getMessage(); 440 return false; 441 } 442 catch (NoSuchMethodException nsme) { 443 errorMessage = nsme.getMessage(); 444 return false; 445 } 446 break; 447 default: 448 break; 449 } 450 return true; 451 } 452 453 462 private static Object locateBrowser() { 463 if (browser != null) { 464 return browser; 465 } 466 switch (jvm) { 467 case MRJ_2_0: 468 try { 469 Integer finderCreatorCode = (Integer )makeOSType.invoke(null, new Object []{FINDER_CREATOR}); 470 Object aeTarget = aeTargetConstructor.newInstance(new Object []{finderCreatorCode}); 471 Integer gurlType = (Integer )makeOSType.invoke(null, new Object []{GURL_EVENT}); 472 Object appleEvent = appleEventConstructor.newInstance(new Object []{gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID}); 473 return appleEvent; 479 } 480 catch (IllegalAccessException iae) { 481 browser = null; 482 errorMessage = iae.getMessage(); 483 return browser; 484 } 485 catch (InstantiationException ie) { 486 browser = null; 487 errorMessage = ie.getMessage(); 488 return browser; 489 } 490 catch (InvocationTargetException ite) { 491 browser = null; 492 errorMessage = ite.getMessage(); 493 return browser; 494 } 495 case MRJ_2_1: 496 File systemFolder; 497 try { 498 systemFolder = (File )findFolder.invoke(null, new Object []{kSystemFolderType}); 499 } 500 catch (IllegalArgumentException iare) { 501 browser = null; 502 errorMessage = iare.getMessage(); 503 return browser; 504 } 505 catch (IllegalAccessException iae) { 506 browser = null; 507 errorMessage = iae.getMessage(); 508 return browser; 509 } 510 catch (InvocationTargetException ite) { 511 browser = null; 512 errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage(); 513 return browser; 514 } 515 String [] systemFolderFiles = systemFolder.list(); 516 for (int i = 0; i < systemFolderFiles.length; i++) { 518 try { 519 File file = new File (systemFolder, systemFolderFiles[i]); 520 if (!file.isFile()) { 521 continue; 522 } 523 Object fileType = getFileType.invoke(null, new Object []{file}); 529 if (FINDER_TYPE.equals(fileType.toString())) { 530 Object fileCreator = getFileCreator.invoke(null, new Object []{file}); 531 if (FINDER_CREATOR.equals(fileCreator.toString())) { 532 browser = file.toString(); return browser; 534 } 535 } 536 } 537 catch (IllegalArgumentException iare) { 538 browser = browser; 539 errorMessage = iare.getMessage(); 540 return null; 541 } 542 catch (IllegalAccessException iae) { 543 browser = null; 544 errorMessage = iae.getMessage(); 545 return browser; 546 } 547 catch (InvocationTargetException ite) { 548 browser = null; 549 errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage(); 550 return browser; 551 } 552 } 553 browser = null; 554 break; 555 case MRJ_3_0: 556 case MRJ_3_1: 557 browser = ""; break; 559 case WINDOWS_NT: 560 browser = "cmd.exe"; 561 break; 562 case WINDOWS_9x: 563 browser = "command.com"; 564 break; 565 case OTHER: 566 default: 567 browser = "netscape"; 568 break; 569 } 570 return browser; 571 } 572 573 579 public static void openURL(String url) throws IOException { 580 if (!loadedWithoutErrors) { 581 throw new IOException ("Exception in finding browser: " + errorMessage); 582 } 583 Object browser = locateBrowser(); 584 if (browser == null) { 585 throw new IOException ("Unable to locate browser: " + errorMessage); 586 } 587 588 switch (jvm) { 589 case MRJ_2_0: 590 Object aeDesc = null; 591 try { 592 aeDesc = aeDescConstructor.newInstance(new Object []{url}); 593 putParameter.invoke(browser, new Object []{keyDirectObject, aeDesc}); 594 sendNoReply.invoke(browser, new Object []{}); 595 } 596 catch (InvocationTargetException ite) { 597 throw new IOException ("InvocationTargetException while creating AEDesc: " + ite.getMessage()); 598 } 599 catch (IllegalAccessException iae) { 600 throw new IOException ("IllegalAccessException while building AppleEvent: " + iae.getMessage()); 601 } 602 catch (InstantiationException ie) { 603 throw new IOException ("InstantiationException while creating AEDesc: " + ie.getMessage()); 604 } 605 finally { 606 aeDesc = null; browser = null; } 609 break; 610 case MRJ_2_1: 611 Runtime.getRuntime().exec(new String []{(String )browser, url}); 612 break; 613 case MRJ_3_0: 614 int[] instance = new int[1]; 615 int result = ICStart(instance, 0); 616 if (result == 0) { 617 int[] selectionStart = new int[]{0}; 618 byte[] urlBytes = url.getBytes(); 619 int[] selectionEnd = new int[]{urlBytes.length}; 620 result = ICLaunchURL(instance[0], new byte[]{0}, urlBytes, 621 urlBytes.length, selectionStart, 622 selectionEnd); 623 if (result == 0) { 624 ICStop(instance); 627 } 628 else { 629 throw new IOException ("Unable to launch URL: " + result); 630 } 631 } 632 else { 633 throw new IOException ("Unable to create an Internet Config instance: " + result); 634 } 635 break; 636 case MRJ_3_1: 637 try { 638 openURL.invoke(null, new Object []{url}); 639 } 640 catch (InvocationTargetException ite) { 641 throw new IOException ("InvocationTargetException while calling openURL: " + ite.getMessage()); 642 } 643 catch (IllegalAccessException iae) { 644 throw new IOException ("IllegalAccessException while calling openURL: " + iae.getMessage()); 645 } 646 break; 647 case WINDOWS_NT: 648 case WINDOWS_9x: 649 Process process = Runtime.getRuntime().exec(new String []{(String )browser, 652 FIRST_WINDOWS_PARAMETER, 653 SECOND_WINDOWS_PARAMETER, 654 THIRD_WINDOWS_PARAMETER, 655 '"' + url + '"'}); 656 try { 659 process.waitFor(); 660 process.exitValue(); 661 } 662 catch (InterruptedException ie) { 663 throw new IOException ("InterruptedException while launching browser: " + ie.getMessage()); 664 } 665 break; 666 case OTHER: 667 669 process = Runtime.getRuntime().exec(new String []{(String )browser, 671 NETSCAPE_REMOTE_PARAMETER, 672 NETSCAPE_OPEN_PARAMETER_START + 673 url + 674 NETSCAPE_OPEN_PARAMETER_END}); 675 try { 676 int exitCode = process.waitFor(); 677 if (exitCode != 0) { Runtime.getRuntime().exec(new String []{(String )browser, url}); 679 } 680 } 681 catch (InterruptedException ie) { 682 throw new IOException ("InterruptedException while launching browser: " + ie.getMessage()); 683 } 684 break; 685 default: 686 Runtime.getRuntime().exec(new String []{(String )browser, url}); 688 break; 689 } 690 } 691 692 696 private native static int ICStart(int[] instance, int signature); 697 698 private native static int ICStop(int[] instance); 699 700 private native static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len, 701 int[] selectionStart, int[] selectionEnd); 702 } 703 704 705 | Popular Tags |