Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
BrowserLauncher.java
1 package ij.plugin;
2 import java.io.File;
3 import java.io.FileNotFoundException;
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 import java.net.URL;
10 import java.net.URLClassLoader;
11 import java.applet.Applet;
12 
60 public class BrowserLauncher implements PlugIn {
61 
63  public void run(String theURL) {
64  if (theURL==null || theURL.equals(""))
65  theURL = "http://rsb.info.nih.gov/ij/";
66  else if (theURL.equals("online"))
67  theURL = "http://rsb.info.nih.gov/ij/docs";
68  Applet applet = ij.IJ.getApplet();
69  if (applet!=null) {
70  try {
71  applet.getAppletContext().showDocument(new URL(theURL), "_blank" );
72  } catch (Exception e) {}
73  return;
74  }
75  try {openURL(theURL);}
76  catch (IOException e) {}
77  }
78 
82  private static int jvm;
83 
85  private static Object browser;
86 
94  private static boolean loadedWithoutErrors;
95 
97  private static Class mrjFileUtilsClass;
98 
100  private static Class mrjOSTypeClass;
101 
103  private static Class aeDescClass;
104 
106  private static Constructor aeTargetConstructor;
107 
109  private static Constructor appleEventConstructor;
110 
112  private static Constructor aeDescConstructor;
113 
115  private static Method findFolder;
116 
118  private static Method getFileCreator;
119 
121  private static Method getFileType;
122 
124  private static Method openURL;
125 
127  private static Method makeOSType;
128 
130  private static Method putParameter;
131 
133  private static Method sendNoReply;
134 
136  private static Object kSystemFolderType;
137 
139  private static Integer keyDirectObject;
140 
142  private static Integer kAutoGenerateReturnID;
143 
145  private static Integer kAnyTransactionID;
146 
148  private static Object linkage;
149 
151  private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
152 
154  private static final int MRJ_2_0 = 0;
155 
157  private static final int MRJ_2_1 = 1;
158 
160  private static final int MRJ_3_0 = 3;
161 
163  private static final int MRJ_3_1 = 4;
164 
166  private static final int WINDOWS = 5;
167 
169  private static final int MACOSX = 6;
170 
172  private static final int OTHER = -1;
173 
178  private static final String FINDER_TYPE = "FNDR";
179 
184  private static final String FINDER_CREATOR = "MACS";
185 
187  private static final String GURL_EVENT = "GURL";
188 
193  private static final String NETSCAPE_REMOTE_PARAMETER = "-remote";
194  private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
195  private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
196 
200  private static String errorMessage;
201 
206  static {
207  loadedWithoutErrors = true;
208  String osName = System.getProperty("os.name");
209  if (osName.startsWith("Mac OS X") )
210  jvm = MACOSX;
211  else if (osName.startsWith("Mac OS")) {
212  String mrjVersion = System.getProperty("mrj.version");
213  String majorMRJVersion = mrjVersion.substring(0, 3);
214  try {
215  double version = Double.valueOf(majorMRJVersion).doubleValue();
216  if (version == 2) {
217  jvm = MRJ_2_0;
218  } else if (version >= 2.1 && version < 3) {
219  // Assume that all 2.x versions of MRJ work the same. MRJ 2.1 actually
220  // works via Runtime.exec() and 2.2 supports that but has an openURL() method
221  // as well that we currently ignore.
222  jvm = MRJ_2_1;
223  } else if (version == 3.0) {
224  jvm = MRJ_3_0;
225  } else if (version >= 3.1) {
226  // Assume that all 3.1 and later versions of MRJ work the same.
227  jvm = MRJ_3_1;
228  } else {
229  loadedWithoutErrors = false;
230  errorMessage = "Unsupported MRJ version: " + version;
231  }
232  } catch (NumberFormatException nfe) {
233  loadedWithoutErrors = false;
234  errorMessage = "Invalid MRJ version: " + mrjVersion;
235  }
236  } else if (osName.startsWith("Windows"))
237  jvm = WINDOWS;
238  else
239  jvm = OTHER;
240 
241  if (loadedWithoutErrors) { // if we haven't hit any errors yet
242  loadedWithoutErrors = loadClasses();
243  }
244  }
245 
249  public BrowserLauncher() { }
250 
257  private static boolean loadClasses() {
258  switch (jvm) {
259  case MRJ_2_1:
260  try {
261  mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
262  mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType");
263  Field systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType");
264  kSystemFolderType = systemFolderField.get(null);
265  findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class[] { mrjOSTypeClass });
266  getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class[] { File.class });
267  getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class[] { File.class });
268  } catch (ClassNotFoundException cnfe) {
269  errorMessage = cnfe.getMessage();
270  return false;
271  } catch (NoSuchFieldException nsfe) {
272  errorMessage = nsfe.getMessage();
273  return false;
274  } catch (NoSuchMethodException nsme) {
275  errorMessage = nsme.getMessage();
276  return false;
277  } catch (SecurityException se) {
278  errorMessage = se.getMessage();
279  return false;
280  } catch (IllegalAccessException iae) {
281  errorMessage = iae.getMessage();
282  return false;
283  }
284  break;
285  case MACOSX:
286  try {
287  if (new File("/System/Library/Java/com/apple/cocoa/application/NSWorkspace.class").exists()){
288  ClassLoader classLoader = new URLClassLoader(new URL[]{new File("/System/Library/Java").toURL()});
289  mrjFileUtilsClass = Class.forName("com.apple.cocoa.application.NSWorkspace", true, classLoader);
290  } else {
291  mrjFileUtilsClass = Class.forName("com.apple.cocoa.application.NSWorkspace");
292  }
293  openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class[] { java.net.URL.class });
294  } catch (Exception e) {
295  ij.IJ.log("MaxOSX: "+e);
296  errorMessage = e.getMessage();
297  return false;
298  }
299  default:
300  break;
301  }
302  return true;
303  }
304 
313  private static Object locateBrowser() {
314  if (browser != null) {
315  return browser;
316  }
317  switch (jvm) {
318  case MRJ_2_0:
319  return null;
320  case MRJ_2_1:
321  File systemFolder;
322  try {
323  systemFolder = (File) findFolder.invoke(null, new Object[] { kSystemFolderType });
324  } catch (IllegalArgumentException iare) {
325  browser = null;
326  errorMessage = iare.getMessage();
327  return browser;
328  } catch (IllegalAccessException iae) {
329  browser = null;
330  errorMessage = iae.getMessage();
331  return browser;
332  } catch (InvocationTargetException ite) {
333  browser = null;
334  errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
335  return browser;
336  }
337  String[] systemFolderFiles = systemFolder.list();
338  // Avoid a FilenameFilter because that can't be stopped mid-list
339  for(int i = 0; i < systemFolderFiles.length; i++) {
340  try {
341  File file = new File(systemFolder, systemFolderFiles[i]);
342  if (!file.isFile()) {
343  continue;
344  }
345  // We're looking for a file with a creator code of 'MACS' and
346  // a type of 'FNDR'. Only requiring the type results in non-Finder
347  // applications being picked up on certain Mac OS 9 systems,
348  // especially German ones, and sending a GURL event to those
349  // applications results in a logout under Multiple Users.
350  Object fileType = getFileType.invoke(null, new Object[] { file });
351  if (FINDER_TYPE.equals(fileType.toString())) {
352  Object fileCreator = getFileCreator.invoke(null, new Object[] { file });
353  if (FINDER_CREATOR.equals(fileCreator.toString())) {
354  browser = file.toString(); // Actually the Finder, but that's OK
355  return browser;
356  }
357  }
358  } catch (IllegalArgumentException iare) {
359  browser = browser;
360  errorMessage = iare.getMessage();
361  return null;
362  } catch (IllegalAccessException iae) {
363  browser = null;
364  errorMessage = iae.getMessage();
365  return browser;
366  } catch (InvocationTargetException ite) {
367  browser = null;
368  errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
369  return browser;
370  }
371  }
372  browser = null;
373  break;
374  case MRJ_3_0:
375  case MRJ_3_1:
376  case WINDOWS:
377  browser = ""; // not used; return something non-null
378  break;
379  case OTHER:
380  default:
381  browser = "netscape";
382  break;
383  }
384  return browser;
385  }
386 
392  public static void openURL(String url) throws IOException {
393  if (!loadedWithoutErrors) {
394  throw new IOException("Exception in finding browser: " + errorMessage);
395  }
396  Object browser = locateBrowser();
397  if (browser == null) {
398  throw new IOException("Unable to locate browser: " + errorMessage);
399  }
400 
401  switch (jvm) {
402  case MRJ_2_1:
403  Runtime.getRuntime().exec(new String[] { (String) browser, url } );
404  break;
405  case MACOSX:
406  try {
407  Method aMethod = mrjFileUtilsClass.getDeclaredMethod("sharedWorkspace", new Class[] {});
408  Object aTarget = aMethod.invoke( mrjFileUtilsClass, new Object[] {});
409  openURL.invoke(aTarget, new Object[] { new java.net.URL( url )});
410  } catch (Exception e) {
411  errorMessage = ""+e;
412  }
413  break;
414  case WINDOWS:
415  String cmd = "rundll32 url.dll,FileProtocolHandler " + url;
416  if (ij.IJ.debugMode) {ij.IJ.log("Exec: "+cmd);}
417  Process process = Runtime.getRuntime().exec(cmd);
418  // This avoids a memory leak on some versions of Java on Windows.
419  // That's hinted at in <http://developer.java.sun.com/developer/qow/archive/68/>.
420  try {
421  process.waitFor();
422  process.exitValue();
423  } catch (InterruptedException ie) {
424  throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
425  }
426  break;
427  case OTHER:
428  // Assume that we're on Unix and that Netscape is installed
429 
430  // First, attempt to open the URL in a currently running session of Netscape
431  process = Runtime.getRuntime().exec(new String[] { (String) browser,
432  NETSCAPE_REMOTE_PARAMETER,
433  NETSCAPE_OPEN_PARAMETER_START +
434  url +
435  NETSCAPE_OPEN_PARAMETER_END });
436  try {
437  int exitCode = process.waitFor();
438  if (exitCode != 0) { // if Netscape was not open
439  Runtime.getRuntime().exec(new String[] { (String) browser, url });
440  }
441  } catch (InterruptedException ie) {
442  throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
443  }
444  break;
445  default:
446  // This should never occur, but if it does, we'll try the simplest thing possible
447  Runtime.getRuntime().exec(new String[] { (String) browser, url });
448  break;
449  }
450  }
451 
456  private native static int ICStart(int[] instance, int signature);
457  private native static int ICStop(int[] instance);
458  private native static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len,
459  int[] selectionStart, int[] selectionEnd);
460 }
461