PageRenderTime 79ms CodeModel.GetById 46ms RepoModel.GetById 0ms app.codeStats 1ms

/core/src/java/com/dtolabs/client/utils/BrowserLauncher.java

https://github.com/ashortland/rundeck
Java | 668 lines | 400 code | 58 blank | 210 comment | 43 complexity | 640b6b9ecb9811c7b6dbe307ac7a6b3f MD5 | raw file
  1. /*
  2. * Copyright 2010 DTO Labs, Inc. (http://dtolabs.com)
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.dtolabs.client.utils;
  17. import java.io.File;
  18. import java.io.IOException;
  19. import java.lang.reflect.Constructor;
  20. import java.lang.reflect.Field;
  21. import java.lang.reflect.InvocationTargetException;
  22. import java.lang.reflect.Method;
  23. public class BrowserLauncher {
  24. /**
  25. * The Java virtual machine that we are running on. Actually, in most cases we only care about the operating
  26. * system, but some operating systems require us to switch on the VM.
  27. */
  28. private static int jvm;
  29. /**
  30. * The browser for the system
  31. */
  32. private static Object browser;
  33. /**
  34. * Caches whether any classes, methods, and fields that are not part of the JDK and need to be dynamically loaded at
  35. * runtime loaded successfully.
  36. * <p/>
  37. * Note that if this is <code>false</code>, <code>openURL()</code> will always return an IOException.
  38. */
  39. private static boolean loadedWithoutErrors;
  40. /**
  41. * The com.apple.mrj.MRJFileUtils class
  42. */
  43. private static Class mrjFileUtilsClass;
  44. /**
  45. * The com.apple.mrj.MRJOSType class
  46. */
  47. private static Class mrjOSTypeClass;
  48. /**
  49. * The com.apple.MacOS.AEDesc class
  50. */
  51. private static Class aeDescClass;
  52. /**
  53. * The <init>(int) method of com.apple.MacOS.AETarget
  54. */
  55. private static Constructor aeTargetConstructor;
  56. /**
  57. * The <init>(int, int, int) method of com.apple.MacOS.AppleEvent
  58. */
  59. private static Constructor appleEventConstructor;
  60. /**
  61. * The <init>(String) method of com.apple.MacOS.AEDesc
  62. */
  63. private static Constructor aeDescConstructor;
  64. /**
  65. * The findFolder method of com.apple.mrj.MRJFileUtils
  66. */
  67. private static Method findFolder;
  68. /**
  69. * The getFileCreator method of com.apple.mrj.MRJFileUtils
  70. */
  71. private static Method getFileCreator;
  72. /**
  73. * The getFileType method of com.apple.mrj.MRJFileUtils
  74. */
  75. private static Method getFileType;
  76. /**
  77. * The openURL method of com.apple.mrj.MRJFileUtils
  78. */
  79. private static Method openURL;
  80. /**
  81. * The makeOSType method of com.apple.MacOS.OSUtils
  82. */
  83. private static Method makeOSType;
  84. /**
  85. * The putParameter method of com.apple.MacOS.AppleEvent
  86. */
  87. private static Method putParameter;
  88. /**
  89. * The sendNoReply method of com.apple.MacOS.AppleEvent
  90. */
  91. private static Method sendNoReply;
  92. /**
  93. * Actually an MRJOSType pointing to the System Folder on a Macintosh
  94. */
  95. private static Object kSystemFolderType;
  96. /**
  97. * The keyDirectObject AppleEvent parameter type
  98. */
  99. private static Integer keyDirectObject;
  100. /**
  101. * The kAutoGenerateReturnID AppleEvent code
  102. */
  103. private static Integer kAutoGenerateReturnID;
  104. /**
  105. * The kAnyTransactionID AppleEvent code
  106. */
  107. private static Integer kAnyTransactionID;
  108. /**
  109. * The linkage object required for JDirect 3 on Mac OS X.
  110. */
  111. private static Object linkage;
  112. /**
  113. * The framework to reference on Mac OS X
  114. */
  115. private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
  116. /**
  117. * JVM constant for MRJ 2.0
  118. */
  119. private static final int MRJ_2_0 = 0;
  120. /**
  121. * JVM constant for MRJ 2.1 or later
  122. */
  123. private static final int MRJ_2_1 = 1;
  124. /**
  125. * JVM constant for Java on Mac OS X 10.0 (MRJ 3.0)
  126. */
  127. private static final int MRJ_3_0 = 3;
  128. /**
  129. * JVM constant for MRJ 3.1
  130. */
  131. private static final int MRJ_3_1 = 4;
  132. /**
  133. * JVM constant for any Windows NT JVM
  134. */
  135. private static final int WINDOWS_NT = 5;
  136. /**
  137. * JVM constant for any Windows 9x JVM
  138. */
  139. private static final int WINDOWS_9x = 6;
  140. /**
  141. * JVM constant for any other platform
  142. */
  143. private static final int OTHER = -1;
  144. /**
  145. * The file type of the Finder on a Macintosh. Hardcoding "Finder" would keep non-U.S. English systems from working
  146. * properly.
  147. */
  148. private static final String FINDER_TYPE = "FNDR";
  149. /**
  150. * The creator code of the Finder on a Macintosh, which is needed to send AppleEvents to the application.
  151. */
  152. private static final String FINDER_CREATOR = "MACS";
  153. /**
  154. * The name for the AppleEvent type corresponding to a GetURL event.
  155. */
  156. private static final String GURL_EVENT = "GURL";
  157. /**
  158. * The first parameter that needs to be passed into Runtime.exec() to open the default web browser on Windows.
  159. */
  160. private static final String FIRST_WINDOWS_PARAMETER = "/c";
  161. /**
  162. * The second parameter for Runtime.exec() on Windows.
  163. */
  164. private static final String SECOND_WINDOWS_PARAMETER = "start";
  165. /**
  166. * The third parameter for Runtime.exec() on Windows. This is a "title" parameter that the command line expects.
  167. * Setting this parameter allows URLs containing spaces to work.
  168. */
  169. private static final String THIRD_WINDOWS_PARAMETER = "\"\"";
  170. /**
  171. * The shell parameters for Netscape that opens a given URL in an already-open copy of Netscape on many command-line
  172. * systems.
  173. */
  174. private static final String NETSCAPE_REMOTE_PARAMETER = "-remote";
  175. private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
  176. private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
  177. /**
  178. * The message from any exception thrown throughout the initialization process.
  179. */
  180. private static String errorMessage;
  181. /**
  182. * An initialization block that determines the operating system and loads the necessary
  183. * runtime data.
  184. */
  185. static {
  186. loadedWithoutErrors = true;
  187. String osName = System.getProperty("os.name");
  188. if (osName.startsWith("Mac OS")) {
  189. String mrjVersion = System.getProperty("mrj.version");
  190. String majorMRJVersion = mrjVersion.substring(0, 3);
  191. try {
  192. double version = Double.valueOf(majorMRJVersion).doubleValue();
  193. if (version == 2) {
  194. jvm = MRJ_2_0;
  195. } else if (version >= 2.1 && version < 3) {
  196. // Assume that all 2.x versions of MRJ work the same. MRJ 2.1 actually
  197. // works via Runtime.exec() and 2.2 supports that but has an openURL() method
  198. // as well that we currently ignore.
  199. jvm = MRJ_2_1;
  200. } else if (version == 3.0) {
  201. jvm = MRJ_3_0;
  202. } else if (version >= 3.1) {
  203. // Assume that all 3.1 and later versions of MRJ work the same.
  204. jvm = MRJ_3_1;
  205. } else {
  206. loadedWithoutErrors = false;
  207. errorMessage = "Unsupported MRJ version: " + version;
  208. }
  209. } catch (NumberFormatException nfe) {
  210. loadedWithoutErrors = false;
  211. errorMessage = "Invalid MRJ version: " + mrjVersion;
  212. }
  213. } else if (osName.startsWith("Windows")) {
  214. if (osName.indexOf("9") != -1) {
  215. jvm = WINDOWS_9x;
  216. } else {
  217. jvm = WINDOWS_NT;
  218. }
  219. } else {
  220. jvm = OTHER;
  221. }
  222. if (loadedWithoutErrors) { // if we haven't hit any errors yet
  223. loadedWithoutErrors = loadClasses();
  224. }
  225. }
  226. /**
  227. * This class should be never be instantiated; this just ensures so.
  228. */
  229. private BrowserLauncher() { }
  230. /**
  231. * Called by a static initializer to load any classes, fields, and methods required at runtime to locate the user's
  232. * web browser.
  233. *
  234. * @return <code>true</code> if all intialization succeeded <code>false</code> if any portion of the initialization
  235. * failed
  236. */
  237. private static boolean loadClasses() {
  238. switch (jvm) {
  239. case MRJ_2_0:
  240. try {
  241. Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
  242. Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
  243. Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent");
  244. Class aeClass = Class.forName("com.apple.MacOS.ae");
  245. aeDescClass = Class.forName("com.apple.MacOS.AEDesc");
  246. aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class[]{int.class});
  247. appleEventConstructor
  248. = appleEventClass.getDeclaredConstructor(
  249. new Class[]{int.class, int.class, aeTargetClass, int.class, int.class});
  250. aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class[]{String.class});
  251. makeOSType = osUtilsClass.getDeclaredMethod("makeOSType", new Class[]{String.class});
  252. putParameter
  253. = appleEventClass.getDeclaredMethod("putParameter", new Class[]{int.class, aeDescClass});
  254. sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply", new Class[]{});
  255. Field keyDirectObjectField = aeClass.getDeclaredField("keyDirectObject");
  256. keyDirectObject = (Integer) keyDirectObjectField.get(null);
  257. Field autoGenerateReturnIDField = appleEventClass.getDeclaredField("kAutoGenerateReturnID");
  258. kAutoGenerateReturnID = (Integer) autoGenerateReturnIDField.get(null);
  259. Field anyTransactionIDField = appleEventClass.getDeclaredField("kAnyTransactionID");
  260. kAnyTransactionID = (Integer) anyTransactionIDField.get(null);
  261. } catch (ClassNotFoundException cnfe) {
  262. errorMessage = cnfe.getMessage();
  263. return false;
  264. } catch (NoSuchMethodException nsme) {
  265. errorMessage = nsme.getMessage();
  266. return false;
  267. } catch (NoSuchFieldException nsfe) {
  268. errorMessage = nsfe.getMessage();
  269. return false;
  270. } catch (IllegalAccessException iae) {
  271. errorMessage = iae.getMessage();
  272. return false;
  273. }
  274. break;
  275. case MRJ_2_1:
  276. try {
  277. mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
  278. mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType");
  279. Field systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType");
  280. kSystemFolderType = systemFolderField.get(null);
  281. findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class[]{mrjOSTypeClass});
  282. getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class[]{File.class});
  283. getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class[]{File.class});
  284. } catch (ClassNotFoundException cnfe) {
  285. errorMessage = cnfe.getMessage();
  286. return false;
  287. } catch (NoSuchFieldException nsfe) {
  288. errorMessage = nsfe.getMessage();
  289. return false;
  290. } catch (NoSuchMethodException nsme) {
  291. errorMessage = nsme.getMessage();
  292. return false;
  293. } catch (SecurityException se) {
  294. errorMessage = se.getMessage();
  295. return false;
  296. } catch (IllegalAccessException iae) {
  297. errorMessage = iae.getMessage();
  298. return false;
  299. }
  300. break;
  301. case MRJ_3_0:
  302. try {
  303. Class linker = Class.forName("com.apple.mrj.jdirect.Linker");
  304. Constructor constructor = linker.getConstructor(new Class[]{Class.class});
  305. linkage = constructor.newInstance(new Object[]{BrowserLauncher.class});
  306. } catch (ClassNotFoundException cnfe) {
  307. errorMessage = cnfe.getMessage();
  308. return false;
  309. } catch (NoSuchMethodException nsme) {
  310. errorMessage = nsme.getMessage();
  311. return false;
  312. } catch (InvocationTargetException ite) {
  313. errorMessage = ite.getMessage();
  314. return false;
  315. } catch (InstantiationException ie) {
  316. errorMessage = ie.getMessage();
  317. return false;
  318. } catch (IllegalAccessException iae) {
  319. errorMessage = iae.getMessage();
  320. return false;
  321. }
  322. break;
  323. case MRJ_3_1:
  324. try {
  325. mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
  326. openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class[]{String.class});
  327. } catch (ClassNotFoundException cnfe) {
  328. errorMessage = cnfe.getMessage();
  329. return false;
  330. } catch (NoSuchMethodException nsme) {
  331. errorMessage = nsme.getMessage();
  332. return false;
  333. }
  334. break;
  335. default:
  336. break;
  337. }
  338. return true;
  339. }
  340. /**
  341. * Attempts to locate the default web browser on the local system. Caches results so it only locates the browser
  342. * once for each use of this class per JVM instance.
  343. *
  344. * @return The browser for the system. Note that this may not be what you would consider to be a standard web
  345. * browser; instead, it's the application that gets called to open the default web browser. In some cases,
  346. * this will be a non-String object that provides the means of calling the default browser.
  347. */
  348. private static Object locateBrowser() {
  349. if (browser != null) {
  350. return browser;
  351. }
  352. switch (jvm) {
  353. case MRJ_2_0:
  354. try {
  355. Integer finderCreatorCode = (Integer) makeOSType.invoke(null, new Object[]{FINDER_CREATOR});
  356. Object aeTarget = aeTargetConstructor.newInstance(new Object[]{finderCreatorCode});
  357. Integer gurlType = (Integer) makeOSType.invoke(null, new Object[]{GURL_EVENT});
  358. Object appleEvent = appleEventConstructor.newInstance(
  359. new Object[]{gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID});
  360. // Don't set browser = appleEvent because then the next time we call
  361. // locateBrowser(), we'll get the same AppleEvent, to which we'll already have
  362. // added the relevant parameter. Instead, regenerate the AppleEvent every time.
  363. // There's probably a way to do this better; if any has any ideas, please let
  364. // me know.
  365. return appleEvent;
  366. } catch (IllegalAccessException iae) {
  367. browser = null;
  368. errorMessage = iae.getMessage();
  369. return browser;
  370. } catch (InstantiationException ie) {
  371. browser = null;
  372. errorMessage = ie.getMessage();
  373. return browser;
  374. } catch (InvocationTargetException ite) {
  375. browser = null;
  376. errorMessage = ite.getMessage();
  377. return browser;
  378. }
  379. case MRJ_2_1:
  380. File systemFolder;
  381. try {
  382. systemFolder = (File) findFolder.invoke(null, new Object[]{kSystemFolderType});
  383. } catch (IllegalArgumentException iare) {
  384. browser = null;
  385. errorMessage = iare.getMessage();
  386. return browser;
  387. } catch (IllegalAccessException iae) {
  388. browser = null;
  389. errorMessage = iae.getMessage();
  390. return browser;
  391. } catch (InvocationTargetException ite) {
  392. browser = null;
  393. errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
  394. return browser;
  395. }
  396. String[] systemFolderFiles = systemFolder.list();
  397. // Avoid a FilenameFilter because that can't be stopped mid-list
  398. for (int i = 0; i < systemFolderFiles.length; i++) {
  399. try {
  400. File file = new File(systemFolder, systemFolderFiles[i]);
  401. if (!file.isFile()) {
  402. continue;
  403. }
  404. // We're looking for a file with a creator code of 'MACS' and
  405. // a type of 'FNDR'. Only requiring the type results in non-Finder
  406. // applications being picked up on certain Mac OS 9 systems,
  407. // especially German ones, and sending a GURL event to those
  408. // applications results in a logout under Multiple Users.
  409. Object fileType = getFileType.invoke(null, new Object[]{file});
  410. if (FINDER_TYPE.equals(fileType.toString())) {
  411. Object fileCreator = getFileCreator.invoke(null, new Object[]{file});
  412. if (FINDER_CREATOR.equals(fileCreator.toString())) {
  413. browser = file.toString(); // Actually the Finder, but that's OK
  414. return browser;
  415. }
  416. }
  417. } catch (IllegalArgumentException iare) {
  418. BrowserLauncher.browser = browser;
  419. errorMessage = iare.getMessage();
  420. return null;
  421. } catch (IllegalAccessException iae) {
  422. browser = null;
  423. errorMessage = iae.getMessage();
  424. return browser;
  425. } catch (InvocationTargetException ite) {
  426. browser = null;
  427. errorMessage = ite.getTargetException().getClass() + ": "
  428. + ite.getTargetException().getMessage();
  429. return browser;
  430. }
  431. }
  432. browser = null;
  433. break;
  434. case MRJ_3_0:
  435. case MRJ_3_1:
  436. browser = ""; // Return something non-null
  437. break;
  438. case WINDOWS_NT:
  439. browser = "cmd.exe";
  440. break;
  441. case WINDOWS_9x:
  442. browser = "command.com";
  443. break;
  444. case OTHER:
  445. default:
  446. browser = "netscape";
  447. break;
  448. }
  449. return browser;
  450. }
  451. /**
  452. * Attempts to open the default web browser to the given URL.
  453. *
  454. * @param url The URL to open
  455. *
  456. * @throws IOException If the web browser could not be located or does not run
  457. */
  458. public static void openURL(String url, String browser) throws IOException {
  459. if (browser == null) {
  460. BrowserLauncher.openURL(url);
  461. }
  462. // if (browser.indexOf(" ") > -1) { //has blank spaces
  463. // if (! browser.startsWith("\"")) browser = "\"" + browser;
  464. // if (! browser.endsWith("\"")) browser = browser + "\"";
  465. // }
  466. if (browser.indexOf("%1") > -1) {
  467. String command = browser.substring(0, browser.indexOf("%1")) + url
  468. + browser.substring(browser.indexOf("%1") + 2);
  469. Process process = Runtime.getRuntime().exec(new String[]{command});
  470. } else {
  471. Process process = Runtime.getRuntime().exec(new String[]{browser, url});
  472. }
  473. // try {
  474. // process.waitFor();
  475. // process.exitValue();
  476. // } catch (InterruptedException ie) {
  477. // throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
  478. // }
  479. }
  480. /**
  481. * Attempts to open the web browser to the given URL.
  482. *
  483. * @param url The URL to open
  484. * @param userBrowser The web browser command-line argument
  485. *
  486. * @throws IOException If the web browser could not be located or does not run
  487. */
  488. public static void openURL(String url) throws IOException {
  489. if (!loadedWithoutErrors) {
  490. throw new IOException("Exception in finding browser: " + errorMessage);
  491. }
  492. Object browser = locateBrowser();
  493. if (browser == null) {
  494. throw new IOException("Unable to locate browser: " + errorMessage);
  495. }
  496. switch (jvm) {
  497. case MRJ_2_0:
  498. Object aeDesc = null;
  499. try {
  500. aeDesc = aeDescConstructor.newInstance(new Object[]{url});
  501. putParameter.invoke(browser, new Object[]{keyDirectObject, aeDesc});
  502. sendNoReply.invoke(browser, new Object[]{});
  503. } catch (InvocationTargetException ite) {
  504. throw new IOException("InvocationTargetException while creating AEDesc: " + ite.getMessage());
  505. } catch (IllegalAccessException iae) {
  506. throw new IOException("IllegalAccessException while building AppleEvent: " + iae.getMessage());
  507. } catch (InstantiationException ie) {
  508. throw new IOException("InstantiationException while creating AEDesc: " + ie.getMessage());
  509. } finally {
  510. aeDesc = null; // Encourage it to get disposed if it was created
  511. browser = null; // Ditto
  512. }
  513. break;
  514. case MRJ_2_1:
  515. Runtime.getRuntime().exec(new String[]{(String) browser, url});
  516. break;
  517. case MRJ_3_0:
  518. int[] instance = new int[1];
  519. int result = ICStart(instance, 0);
  520. if (result == 0) {
  521. int[] selectionStart = new int[]{0};
  522. byte[] urlBytes = url.getBytes();
  523. int[] selectionEnd = new int[]{urlBytes.length};
  524. result = ICLaunchURL(instance[0], new byte[]{0}, urlBytes,
  525. urlBytes.length, selectionStart,
  526. selectionEnd);
  527. if (result == 0) {
  528. // Ignore the return value; the URL was launched successfully
  529. // regardless of what happens here.
  530. ICStop(instance);
  531. } else {
  532. throw new IOException("Unable to launch URL: " + result);
  533. }
  534. } else {
  535. throw new IOException("Unable to create an Internet Config instance: " + result);
  536. }
  537. break;
  538. case MRJ_3_1:
  539. try {
  540. openURL.invoke(null, new Object[]{url});
  541. } catch (InvocationTargetException ite) {
  542. throw new IOException("InvocationTargetException while calling openURL: " + ite.getMessage());
  543. } catch (IllegalAccessException iae) {
  544. throw new IOException("IllegalAccessException while calling openURL: " + iae.getMessage());
  545. }
  546. break;
  547. case WINDOWS_NT:
  548. case WINDOWS_9x:
  549. // Add quotes around the URL to allow ampersands and other special
  550. // characters to work.
  551. Process process = Runtime.getRuntime().exec(new String[]{
  552. (String) browser,
  553. FIRST_WINDOWS_PARAMETER,
  554. SECOND_WINDOWS_PARAMETER,
  555. THIRD_WINDOWS_PARAMETER,
  556. '"' + url + '"'
  557. });
  558. // This avoids a memory leak on some versions of Java on Windows.
  559. // That's hinted at in <http://developer.java.sun.com/developer/qow/archive/68/>.
  560. try {
  561. process.waitFor();
  562. process.exitValue();
  563. } catch (InterruptedException ie) {
  564. throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
  565. }
  566. break;
  567. case OTHER:
  568. // Assume that we're on Unix and that Netscape is installed
  569. // First, attempt to open the URL in a currently running session of Netscape
  570. process = Runtime.getRuntime().exec(new String[]{
  571. (String) browser,
  572. NETSCAPE_REMOTE_PARAMETER,
  573. NETSCAPE_OPEN_PARAMETER_START +
  574. url +
  575. NETSCAPE_OPEN_PARAMETER_END
  576. });
  577. try {
  578. int exitCode = process.waitFor();
  579. if (exitCode != 0) { // if Netscape was not open
  580. Runtime.getRuntime().exec(new String[]{(String) browser, url});
  581. }
  582. } catch (InterruptedException ie) {
  583. throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
  584. }
  585. break;
  586. default:
  587. // This should never occur, but if it does, we'll try the simplest thing possible
  588. Runtime.getRuntime().exec(new String[]{(String) browser, url});
  589. break;
  590. }
  591. }
  592. /**
  593. * Methods required for Mac OS X. The presence of native methods does not cause any problems on other platforms.
  594. */
  595. private native static int ICStart(int[] instance, int signature);
  596. private native static int ICStop(int[] instance);
  597. private native static int ICLaunchURL(int instance,
  598. byte[] hint,
  599. byte[] data,
  600. int len,
  601. int[] selectionStart,
  602. int[] selectionEnd);
  603. static public void main(String[] args) throws Exception {
  604. // BrowserLauncher.openURL("http://thinfeeder.sf.net", "\"C:\\Arquivos de programas\\Mozilla Firefox\\firefox.exe\" -remote \"openURL(%1,new-tab)\"");
  605. // BrowserLauncher.openURL("http://thinfeeder.sf.net", "\"C:\\Arquivos de programas\\Mozilla Firefox\\firefox.exe\"");
  606. // BrowserLauncher.openURL("http://thinfeeder.sf.net", "\"C:\\Arquivos de programas\\Mozilla Firefox\\firefox.exe\" -remote \"openurl(%1)\"");
  607. BrowserLauncher.openURL("http://thinfeeder.sf.net",
  608. "\"C:\\Arquivos de programas\\Mozilla Firefox\\firefox.exe\" -P default \"%1\"");
  609. }
  610. }