PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/common/util/BrowserLauncher.java

https://github.com/rpernavas/sshtools
Java | 472 lines | 346 code | 82 blank | 44 comment | 26 complexity | b8fbb5798afb97dc97f0338e87d682e2 MD5 | raw file
  1. /*
  2. * SSHTools - Java SSH2 API
  3. *
  4. * Copyright (C) 2002 Lee David Painter.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Library General Public License
  8. * as published by the Free Software Foundation; either version 2 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * You may also distribute it and/or modify it under the terms of the
  12. * Apache style J2SSH Software License. A copy of which should have
  13. * been provided with the distribution.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * License document supplied with your distribution for more details.
  19. *
  20. */
  21. package com.sshtools.common.util;
  22. import java.io.File;
  23. import java.io.IOException;
  24. import java.lang.reflect.Constructor;
  25. import java.lang.reflect.Field;
  26. import java.lang.reflect.InvocationTargetException;
  27. import java.lang.reflect.Method;
  28. /**
  29. *
  30. *
  31. * @author $author$
  32. * @version $Revision: 1.14 $
  33. */
  34. public class BrowserLauncher {
  35. private static int jvm;
  36. private static Object browser;
  37. private static boolean loadedWithoutErrors;
  38. private static Class mrjFileUtilsClass;
  39. private static Class mrjOSTypeClass;
  40. private static Class macOSErrorClass;
  41. private static Class aeDescClass;
  42. private static Constructor aeTargetConstructor;
  43. private static Constructor appleEventConstructor;
  44. private static Constructor aeDescConstructor;
  45. private static Method findFolder;
  46. private static Method getFileType;
  47. private static Method makeOSType;
  48. private static Method putParameter;
  49. private static Method sendNoReply;
  50. private static Object kSystemFolderType;
  51. private static Integer keyDirectObject;
  52. private static Integer kAutoGenerateReturnID;
  53. private static Integer kAnyTransactionID;
  54. private static final int MRJ_2_0 = 0;
  55. private static final int MRJ_2_1 = 1;
  56. private static final int WINDOWS_NT = 2;
  57. private static final int WINDOWS_9x = 3;
  58. private static final int OTHER = -1;
  59. private static final String FINDER_TYPE = "FNDR";
  60. private static final String FINDER_CREATOR = "MACS";
  61. private static final String GURL_EVENT = "GURL";
  62. private static final String FIRST_WINDOWS_PARAMETER = "/c";
  63. private static final String SECOND_WINDOWS_PARAMETER = "start";
  64. private static final String NETSCAPE_OPEN_PARAMETER_START =
  65. " -remote 'openURL(";
  66. private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
  67. private static String errorMessage;
  68. static {
  69. loadedWithoutErrors = true;
  70. String osName = System.getProperty("os.name");
  71. if ("Mac OS".equals(osName)) {
  72. String mrjVersion = System.getProperty("mrj.version");
  73. String majorMRJVersion = mrjVersion.substring(0, 3);
  74. try {
  75. double version = Double.valueOf(majorMRJVersion).doubleValue();
  76. if (version == 2) {
  77. jvm = MRJ_2_0;
  78. }
  79. else if (version >= 2.1) {
  80. // For the time being, assume that all post-2.0 versions of MRJ work the same
  81. jvm = MRJ_2_1;
  82. }
  83. else {
  84. loadedWithoutErrors = false;
  85. errorMessage = "Unsupported MRJ version: " + version;
  86. }
  87. }
  88. catch (NumberFormatException nfe) {
  89. loadedWithoutErrors = false;
  90. errorMessage = "Invalid MRJ version: " + mrjVersion;
  91. }
  92. }
  93. else if (osName.startsWith("Windows")) {
  94. if (osName.indexOf("9") != -1) {
  95. jvm = WINDOWS_9x;
  96. }
  97. else {
  98. jvm = WINDOWS_NT;
  99. }
  100. }
  101. else {
  102. jvm = OTHER;
  103. }
  104. if (loadedWithoutErrors) { // if we haven't hit any errors yet
  105. loadedWithoutErrors = loadClasses();
  106. }
  107. }
  108. private BrowserLauncher() {
  109. }
  110. private static boolean loadClasses() {
  111. switch (jvm) {
  112. case MRJ_2_0:
  113. try {
  114. Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
  115. macOSErrorClass = Class.forName("com.apple.MacOS.MacOSError");
  116. Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
  117. Class appleEventClass = Class.forName(
  118. "com.apple.MacOS.AppleEvent");
  119. Class aeClass = Class.forName("com.apple.MacOS.ae");
  120. aeDescClass = Class.forName("com.apple.MacOS.AEDesc");
  121. aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class[] {
  122. int.class
  123. });
  124. appleEventConstructor = appleEventClass.getDeclaredConstructor(new
  125. Class[] {
  126. int.class, int.class, aeTargetClass, int.class,
  127. int.class
  128. });
  129. aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class[] {
  130. String.class
  131. });
  132. makeOSType = osUtilsClass.getDeclaredMethod("makeOSType",
  133. new Class[] {String.class});
  134. putParameter = appleEventClass.getDeclaredMethod("putParameter",
  135. new Class[] {int.class, aeDescClass});
  136. sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply",
  137. new Class[] {});
  138. Field keyDirectObjectField = aeClass.getDeclaredField(
  139. "keyDirectObject");
  140. keyDirectObject = (Integer) keyDirectObjectField.get(null);
  141. Field autoGenerateReturnIDField = appleEventClass
  142. .getDeclaredField("kAutoGenerateReturnID");
  143. kAutoGenerateReturnID = (Integer) autoGenerateReturnIDField.get(null);
  144. Field anyTransactionIDField = appleEventClass.getDeclaredField(
  145. "kAnyTransactionID");
  146. kAnyTransactionID = (Integer) anyTransactionIDField.get(null);
  147. }
  148. catch (ClassNotFoundException cnfe) {
  149. errorMessage = cnfe.getMessage();
  150. return false;
  151. }
  152. catch (NoSuchMethodException nsme) {
  153. errorMessage = nsme.getMessage();
  154. return false;
  155. }
  156. catch (NoSuchFieldException nsfe) {
  157. errorMessage = nsfe.getMessage();
  158. return false;
  159. }
  160. catch (IllegalAccessException iae) {
  161. errorMessage = iae.getMessage();
  162. return false;
  163. }
  164. break;
  165. case MRJ_2_1:
  166. try {
  167. mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
  168. mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType");
  169. Field systemFolderField = mrjFileUtilsClass.getDeclaredField(
  170. "kSystemFolderType");
  171. kSystemFolderType = systemFolderField.get(null);
  172. findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder",
  173. new Class[] {mrjOSTypeClass});
  174. getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType",
  175. new Class[] {File.class});
  176. }
  177. catch (ClassNotFoundException cnfe) {
  178. errorMessage = cnfe.getMessage();
  179. return false;
  180. }
  181. catch (NoSuchFieldException nsfe) {
  182. errorMessage = nsfe.getMessage();
  183. return false;
  184. }
  185. catch (NoSuchMethodException nsme) {
  186. errorMessage = nsme.getMessage();
  187. return false;
  188. }
  189. catch (SecurityException se) {
  190. errorMessage = se.getMessage();
  191. return false;
  192. }
  193. catch (IllegalAccessException iae) {
  194. errorMessage = iae.getMessage();
  195. return false;
  196. }
  197. break;
  198. }
  199. return true;
  200. }
  201. private static Object locateBrowser() {
  202. if (browser != null) {
  203. return browser;
  204. }
  205. switch (jvm) {
  206. case MRJ_2_0:
  207. try {
  208. Integer finderCreatorCode = (Integer) makeOSType.invoke(null,
  209. new Object[] {FINDER_CREATOR});
  210. Object aeTarget = aeTargetConstructor.newInstance(new Object[] {
  211. finderCreatorCode
  212. });
  213. Integer gurlType = (Integer) makeOSType.invoke(null,
  214. new Object[] {GURL_EVENT});
  215. Object appleEvent = appleEventConstructor.newInstance(new Object[] {
  216. gurlType, gurlType, aeTarget, kAutoGenerateReturnID,
  217. kAnyTransactionID
  218. });
  219. // Don't set browser = appleEvent because then the next time we call
  220. // locateBrowser(), we'll get the same AppleEvent, to which we'll already have
  221. // added the relevant parameter. Instead, regenerate the AppleEvent every time.
  222. // There's probably a way to do this better; if any has any ideas, please let
  223. // me know.
  224. return appleEvent;
  225. }
  226. catch (IllegalAccessException iae) {
  227. browser = null;
  228. errorMessage = iae.getMessage();
  229. return browser;
  230. }
  231. catch (InstantiationException ie) {
  232. browser = null;
  233. errorMessage = ie.getMessage();
  234. return browser;
  235. }
  236. catch (InvocationTargetException ite) {
  237. browser = null;
  238. errorMessage = ite.getMessage();
  239. return browser;
  240. }
  241. case MRJ_2_1:
  242. File systemFolder;
  243. try {
  244. systemFolder = (File) findFolder.invoke(null,
  245. new Object[] {kSystemFolderType});
  246. }
  247. catch (IllegalArgumentException iare) {
  248. browser = null;
  249. errorMessage = iare.getMessage();
  250. return browser;
  251. }
  252. catch (IllegalAccessException iae) {
  253. browser = null;
  254. errorMessage = iae.getMessage();
  255. return browser;
  256. }
  257. catch (InvocationTargetException ite) {
  258. browser = null;
  259. errorMessage = ite.getTargetException().getClass() + ": "
  260. + ite.getTargetException().getMessage();
  261. return browser;
  262. }
  263. String[] systemFolderFiles = systemFolder.list();
  264. // Avoid a FilenameFilter because that can't be stopped mid-list
  265. for (int i = 0; i < systemFolderFiles.length; i++) {
  266. try {
  267. File file = new File(systemFolder, systemFolderFiles[i]);
  268. if (!file.isFile()) {
  269. continue;
  270. }
  271. Object fileType = getFileType.invoke(null,
  272. new Object[] {file});
  273. if (FINDER_TYPE.equals(fileType.toString())) {
  274. browser = file.toString(); // Actually the Finder, but that's OK
  275. return browser;
  276. }
  277. }
  278. catch (IllegalArgumentException iare) {
  279. browser = browser;
  280. errorMessage = iare.getMessage();
  281. return null;
  282. }
  283. catch (IllegalAccessException iae) {
  284. browser = null;
  285. errorMessage = iae.getMessage();
  286. return browser;
  287. }
  288. catch (InvocationTargetException ite) {
  289. browser = null;
  290. errorMessage = ite.getTargetException().getClass() + ": "
  291. + ite.getTargetException().getMessage();
  292. return browser;
  293. }
  294. }
  295. browser = null;
  296. break;
  297. case WINDOWS_NT:
  298. browser = "cmd.exe";
  299. break;
  300. case WINDOWS_9x:
  301. browser = "command.com";
  302. break;
  303. case OTHER:
  304. default:
  305. //browser = "netscape"; surely mozilla is the thing these days
  306. browser = "mozilla";
  307. break;
  308. }
  309. return browser;
  310. }
  311. /**
  312. *
  313. *
  314. * @param url
  315. *
  316. * @throws IOException
  317. */
  318. public static void openURL(String url) throws IOException {
  319. if (!loadedWithoutErrors) {
  320. throw new IOException("Exception in finding browser: "
  321. + errorMessage);
  322. }
  323. Object browser = locateBrowser();
  324. if (browser == null) {
  325. throw new IOException("Unable to locate browser: " + errorMessage);
  326. }
  327. switch (jvm) {
  328. case MRJ_2_0:
  329. Object aeDesc = null;
  330. try {
  331. aeDesc = aeDescConstructor.newInstance(new Object[] {url});
  332. putParameter.invoke(browser,
  333. new Object[] {keyDirectObject, aeDesc});
  334. sendNoReply.invoke(browser, new Object[] {});
  335. }
  336. catch (InvocationTargetException ite) {
  337. throw new IOException(
  338. "InvocationTargetException while creating AEDesc: "
  339. + ite.getMessage());
  340. }
  341. catch (IllegalAccessException iae) {
  342. throw new IOException(
  343. "IllegalAccessException while building AppleEvent: "
  344. + iae.getMessage());
  345. }
  346. catch (InstantiationException ie) {
  347. throw new IOException(
  348. "InstantiationException while creating AEDesc: "
  349. + ie.getMessage());
  350. }
  351. finally {
  352. aeDesc = null; // Encourage it to get disposed if it was created
  353. browser = null; // Ditto
  354. }
  355. break;
  356. case MRJ_2_1:
  357. Runtime.getRuntime().exec(new String[] { (String) browser, url});
  358. break;
  359. case WINDOWS_NT:
  360. case WINDOWS_9x:
  361. Runtime.getRuntime().exec(new String[] {
  362. (String) browser, FIRST_WINDOWS_PARAMETER,
  363. SECOND_WINDOWS_PARAMETER, url
  364. });
  365. break;
  366. case OTHER:
  367. // Assume that we're on Unix and that Netscape is installed
  368. // First, attempt to open the URL in a currently running session of Netscape
  369. Process process = Runtime.getRuntime().exec( (String) browser
  370. + NETSCAPE_OPEN_PARAMETER_START + url
  371. + NETSCAPE_OPEN_PARAMETER_END);
  372. try {
  373. int exitCode = process.waitFor();
  374. if (exitCode != 0) { // if Netscape was not open
  375. Runtime.getRuntime().exec(new String[] { (String) browser, url});
  376. }
  377. }
  378. catch (InterruptedException ie) {
  379. throw new IOException(
  380. "InterruptedException while launching browser: "
  381. + ie.getMessage());
  382. }
  383. break;
  384. default:
  385. // This should never occur, but if it does, we'll try the simplest thing possible
  386. Runtime.getRuntime().exec(new String[] { (String) browser, url});
  387. break;
  388. }
  389. }
  390. }