/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.gwt.dev.util; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; /** * Provides a platform and JDK-independent method of launching a browser * given a URI. * * <p>Portions derived from public-domain code at * <pre>http://www.centerkey.com/java/browser/</pre> */ public class BrowserLauncher { /** * A browser launcher that uses JDK 1.6 Desktop.browse support. */ private static class Jdk16Launcher extends ReflectiveLauncher { /** * Create a Jdk16Launcher if supported. * * @throws UnsupportedOperationException if not supported */ public Jdk16Launcher() throws UnsupportedOperationException { try { Class<?> desktopClass = Class.forName("java.awt.Desktop"); browseMethod = desktopClass.getMethod("browse", URI.class); Method factory = desktopClass.getMethod("getDesktop"); browseObject = factory.invoke(null); return; } catch (ClassNotFoundException e) { // not on JDK 1.6, try other methods } catch (NoSuchMethodException e) { // not on JDK 1.6, try other methods } catch (SecurityException e) { // ignore, try other methods } catch (IllegalArgumentException e) { // ignore, try other methods } catch (IllegalAccessException e) { // ignore, try other methods } catch (InvocationTargetException e) { // ignore, try other methods } throw new UnsupportedOperationException("no JDK 1.6 Desktop.browse"); } @Override protected Object convertUrl(String url) throws URISyntaxException, MalformedURLException { return new URL(url).toURI(); } } private interface Launcher { void browse(String url) throws IOException, URISyntaxException; } /** * Launch the default browser on Mac via FileManager openURL. */ private static class MacLauncher extends ReflectiveLauncher { public MacLauncher() throws UnsupportedOperationException { Throwable caught = null; try { Class<?> fileManager = Class.forName("com.apple.eio.FileManager"); browseMethod = fileManager.getMethod("openURL", String.class); browseObject = null; return; } catch (SecurityException e) { caught = e; } catch (ClassNotFoundException e) { caught = e; } catch (NoSuchMethodException e) { caught = e; } throw new UnsupportedOperationException("Can't get openURL", caught); } } /** * Interface for launching a URL in a browser, which uses reflection. * * <p>Subclass must set browseObject and browseMethod appropriately. */ private abstract static class ReflectiveLauncher implements Launcher { protected Object browseObject; protected Method browseMethod; public void browse(String url) throws IOException, URISyntaxException { Object arg = convertUrl(url); Throwable caught = null; try { browseMethod.invoke(browseObject, arg); return; } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof IOException) { throw (IOException) cause; } caught = e; } catch (IllegalAccessException e) { caught = e; } throw new RuntimeException("Unexpected exception", caught); } /** * Convert the URL into another form if required. The default * implementation simply returns the unmodified string. * * @param url URL in string form * @return the URL in the form needed for browseMethod * @throws URISyntaxException * @throws MalformedURLException */ protected Object convertUrl(String url) throws URISyntaxException, MalformedURLException { return url; } } /** * Launch a browser by searching for a browser executable on the path. */ private static class UnixExecBrowserLauncher implements Launcher { private static final String[] browsers = { "firefox", "opera", "konqueror", "chrome", "chromium", "epiphany", "seamonkey", "mozilla", "netscape", "galeon", "kazehakase", }; private String browserExecutable; /** * Creates a launcher by searching for a suitable browser executable. * Assumes the presence of the "which" command. * * @throws UnsupportedOperationException if no suitable browser can be * found. */ public UnixExecBrowserLauncher() throws UnsupportedOperationException { for (String browser : browsers) { try { Process process = Runtime.getRuntime().exec(new String[] { "which", browser}); if (process.waitFor() == 0) { browserExecutable = browser; return; } } catch (IOException e) { // ignore, try next one } catch (InterruptedException e) { // ignore, try next one } } throw new UnsupportedOperationException("no suitable browser found"); } public void browse(String url) throws IOException { Runtime.getRuntime().exec(new String[] { browserExecutable, url }); // TODO(jat): do we need to wait for it to exit and check exit status? // That would be best for Firefox, but bad for some of the other browsers. } } /** * Launch the default browser on Windows via the URL protocol handler. */ private static class WindowsLauncher implements Launcher { public void browse(String url) throws IOException { Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url); // TODO(jat): do we need to wait for it to exit and check exit status? } } private static Launcher launcher; /** * Browse to a given URI. * * @param url * @throws IOException * @throws URISyntaxException */ public static void browse(String url) throws IOException, URISyntaxException { if (launcher == null) { findLauncher(); } launcher.browse(url); } /** * Main method so this can be run from the command line for testing. * * @param args URL to launch * @throws URISyntaxException * @throws IOException */ public static void main(String[] args) throws IOException, URISyntaxException { if (args.length == 0) { System.err.println("Usage: BrowserLauncher url..."); System.exit(1); } for (String url : args) { browse(url); } } /** * Initialize launcher to an appropriate one for the current platform/JDK. */ private static void findLauncher() { try { launcher = new Jdk16Launcher(); return; } catch (UnsupportedOperationException e) { // ignore and try other methods } String osName = System.getProperty("os.name"); if (osName.startsWith("Mac OS")) { launcher = new MacLauncher(); } else if (osName.startsWith("Windows")) { launcher = new WindowsLauncher(); } else { launcher = new UnixExecBrowserLauncher(); // let UnsupportedOperationException escape to caller } } }