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