001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package com.sun.servicetag;
043:
044: import java.lang.reflect.Field;
045: import java.lang.reflect.Method;
046: import java.lang.reflect.InvocationTargetException;
047: import java.io.IOException;
048: import java.net.URI;
049:
050: /**
051: * BrowserSupport class.
052: *
053: * The implementation of the com.sun.servicetag API needs to be
054: * compiled with JDK 5 as well since the consumer of this API
055: * may require to support JDK 5 (e.g. NetBeans).
056: *
057: * The Desktop.browse() method can be backported in this class
058: * if needed. The current implementation only supports JDK 6.
059: */
060: class BrowserSupport {
061: private static boolean isBrowseSupported = false;
062: private static Method browseMethod = null;
063: private static Object desktop = null;
064: private static volatile Boolean result = false;
065:
066: private static void initX() {
067: if (desktop != null) {
068: return;
069: }
070: boolean supported = false;
071: Method browseM = null;
072: Object desktopObj = null;
073: try {
074: // Determine if java.awt.Desktop is supported
075: Class desktopCls = Class.forName("java.awt.Desktop", true,
076: null);
077: Method getDesktopM = desktopCls.getMethod("getDesktop");
078: browseM = desktopCls.getMethod("browse", URI.class);
079:
080: Class actionCls = Class.forName("java.awt.Desktop$Action",
081: true, null);
082: final Method isDesktopSupportedMethod = desktopCls
083: .getMethod("isDesktopSupported");
084: Method isSupportedMethod = desktopCls.getMethod(
085: "isSupported", actionCls);
086: Field browseField = actionCls.getField("BROWSE");
087: // isDesktopSupported calls getDefaultToolkit which can block
088: // infinitely, see 6636099 for details, to workaround we call
089: // in a thread and time it out, noting that the issue is specific
090: // to X11, it does not hurt for Windows.
091: Thread xthread = new Thread() {
092: public void run() {
093: try {
094: // support only if Desktop.isDesktopSupported() and
095: // Desktop.isSupported(Desktop.Action.BROWSE) return true.
096: result = (Boolean) isDesktopSupportedMethod
097: .invoke(null);
098: } catch (IllegalAccessException e) {
099: // should never reach here
100: InternalError x = new InternalError(
101: "Desktop.getDesktop() method not found");
102: x.initCause(e);
103: } catch (InvocationTargetException e) {
104: // browser not supported
105: if (Util.isVerbose()) {
106: e.printStackTrace();
107: }
108: }
109: }
110: };
111: // set it to daemon, so that the vm will exit.
112: xthread.setDaemon(true);
113: xthread.start();
114: try {
115: xthread.join(5 * 1000);
116: } catch (InterruptedException ie) {
117: // ignore the exception
118: }
119: if (result.booleanValue()) {
120: desktopObj = getDesktopM.invoke(null);
121: result = (Boolean) isSupportedMethod.invoke(desktopObj,
122: browseField.get(null));
123: supported = result.booleanValue();
124: }
125: } catch (ClassNotFoundException e) {
126: // browser not supported
127: if (Util.isVerbose()) {
128: e.printStackTrace();
129: }
130: } catch (NoSuchMethodException e) {
131: // browser not supported
132: if (Util.isVerbose()) {
133: e.printStackTrace();
134: }
135: } catch (NoSuchFieldException e) {
136: // browser not supported
137: if (Util.isVerbose()) {
138: e.printStackTrace();
139: }
140: } catch (IllegalAccessException e) {
141: // should never reach here
142: InternalError x = new InternalError(
143: "Desktop.getDesktop() method not found");
144: x.initCause(e);
145: throw x;
146: } catch (InvocationTargetException e) {
147: // browser not supported
148: if (Util.isVerbose()) {
149: e.printStackTrace();
150: }
151: }
152: isBrowseSupported = supported;
153: browseMethod = browseM;
154: desktop = desktopObj;
155: }
156:
157: static boolean isSupported() {
158: initX();
159: return isBrowseSupported;
160: }
161:
162: /**
163: * Launches the default browser to display a {@code URI}.
164: * If the default browser is not able to handle the specified
165: * {@code URI}, the application registered for handling
166: * {@code URIs} of the specified type is invoked. The application
167: * is determined from the protocol and path of the {@code URI}, as
168: * defined by the {@code URI} class.
169: * <p>
170: * This method calls the Desktop.getDesktop().browse() method.
171: * <p>
172: * @param uri the URI to be displayed in the user default browser
173: *
174: * @throws NullPointerException if {@code uri} is {@code null}
175: * @throws UnsupportedOperationException if the current platform
176: * does not support the {@link Desktop.Action#BROWSE} action
177: * @throws IOException if the user default browser is not found,
178: * or it fails to be launched, or the default handler application
179: * failed to be launched
180: * @throws IllegalArgumentException if the necessary permissions
181: * are not available and the URI can not be converted to a {@code URL}
182: */
183: static void browse(URI uri) throws IOException {
184: if (uri == null) {
185: throw new NullPointerException("null uri");
186: }
187: if (!isSupported()) {
188: throw new UnsupportedOperationException(
189: "Browse operation is not supported");
190: }
191:
192: // Call Desktop.browse() method
193: try {
194: if (Util.isVerbose()) {
195: System.out.println("desktop: " + desktop
196: + ":browsing..." + uri);
197: }
198: browseMethod.invoke(desktop, uri);
199: } catch (IllegalAccessException e) {
200: // should never reach here
201: InternalError x = new InternalError(
202: "Desktop.getDesktop() method not found");
203: x.initCause(e);
204: throw x;
205: } catch (InvocationTargetException e) {
206: Throwable x = e.getCause();
207: if (x != null) {
208: if (x instanceof UnsupportedOperationException) {
209: throw (UnsupportedOperationException) x;
210: } else if (x instanceof IllegalArgumentException) {
211: throw (IllegalArgumentException) x;
212: } else if (x instanceof IOException) {
213: throw (IOException) x;
214: } else if (x instanceof SecurityException) {
215: throw (SecurityException) x;
216: } else {
217: // ignore
218: }
219: }
220: }
221: }
222: }
|