duke@1: /* jjg@1413: * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: package javax.tools; duke@1: duke@1: import java.io.File; jjg@659: import java.lang.ref.Reference; jjg@659: import java.lang.ref.WeakReference; duke@1: import java.net.URL; duke@1: import java.net.URLClassLoader; duke@1: import java.net.MalformedURLException; jjg@659: import java.util.HashMap; duke@1: import java.util.Locale; jjg@659: import java.util.Map; duke@1: import java.util.logging.Logger; duke@1: import java.util.logging.Level; duke@1: import static java.util.logging.Level.*; duke@1: duke@1: /** duke@1: * Provides methods for locating tool providers, for example, duke@1: * providers of compilers. This class complements the duke@1: * functionality of {@link java.util.ServiceLoader}. duke@1: * duke@1: * @author Peter von der Ahé duke@1: * @since 1.6 duke@1: */ duke@1: public class ToolProvider { duke@1: duke@1: private static final String propertyName = "sun.tools.ToolProvider"; duke@1: private static final String loggerName = "javax.tools"; duke@1: duke@1: /* duke@1: * Define the system property "sun.tools.ToolProvider" to enable duke@1: * debugging: duke@1: * duke@1: * java ... -Dsun.tools.ToolProvider ... duke@1: */ duke@1: static T trace(Level level, Object reason) { duke@1: // NOTE: do not make this method private as it affects stack traces duke@1: try { duke@1: if (System.getProperty(propertyName) != null) { duke@1: StackTraceElement[] st = Thread.currentThread().getStackTrace(); duke@1: String method = "???"; duke@1: String cls = ToolProvider.class.getName(); duke@1: if (st.length > 2) { duke@1: StackTraceElement frame = st[2]; duke@1: method = String.format((Locale)null, "%s(%s:%s)", duke@1: frame.getMethodName(), duke@1: frame.getFileName(), duke@1: frame.getLineNumber()); duke@1: cls = frame.getClassName(); duke@1: } duke@1: Logger logger = Logger.getLogger(loggerName); duke@1: if (reason instanceof Throwable) { duke@1: logger.logp(level, cls, method, duke@1: reason.getClass().getName(), (Throwable)reason); duke@1: } else { duke@1: logger.logp(level, cls, method, String.valueOf(reason)); duke@1: } duke@1: } duke@1: } catch (SecurityException ex) { duke@1: System.err.format((Locale)null, "%s: %s; %s%n", duke@1: ToolProvider.class.getName(), duke@1: reason, duke@1: ex.getLocalizedMessage()); duke@1: } duke@1: return null; duke@1: } duke@1: jjg@659: private static final String defaultJavaCompilerName jjg@659: = "com.sun.tools.javac.api.JavacTool"; jjg@659: duke@1: /** duke@1: * Gets the Java™ programming language compiler provided duke@1: * with this platform. duke@1: * @return the compiler provided with this platform or duke@1: * {@code null} if no compiler is provided duke@1: */ duke@1: public static JavaCompiler getSystemJavaCompiler() { jjg@659: return instance().getSystemTool(JavaCompiler.class, defaultJavaCompilerName); duke@1: } duke@1: jjg@1413: private static final String defaultDocumentationToolName jjg@1413: = "com.sun.tools.javadoc.api.JavadocTool"; jjg@1413: jjg@1413: /** jjg@1413: * Gets the Java™ programming language documentation tool provided jjg@1413: * with this platform. jjg@1413: * @return the documentation tool provided with this platform or jjg@1413: * {@code null} if no documentation tool is provided jjg@1413: */ jjg@1413: public static DocumentationTool getSystemDocumentationTool() { jjg@1413: return instance().getSystemTool(DocumentationTool.class, defaultDocumentationToolName); jjg@1413: } jjg@1413: duke@1: /** duke@1: * Returns the class loader for tools provided with this platform. duke@1: * This does not include user-installed tools. Use the duke@1: * {@linkplain java.util.ServiceLoader service provider mechanism} duke@1: * for locating user installed tools. duke@1: * duke@1: * @return the class loader for tools provided with this platform duke@1: * or {@code null} if no tools are provided duke@1: */ duke@1: public static ClassLoader getSystemToolClassLoader() { jjg@659: try { jjg@659: Class c = jjg@659: instance().getSystemToolClass(JavaCompiler.class, defaultJavaCompilerName); jjg@659: return c.getClassLoader(); jjg@659: } catch (Throwable e) { jjg@659: return trace(WARNING, e); jjg@659: } duke@1: } duke@1: jjg@659: jjg@659: private static ToolProvider instance; jjg@659: jjg@659: private static synchronized ToolProvider instance() { jjg@659: if (instance == null) jjg@659: instance = new ToolProvider(); jjg@659: return instance; jjg@659: } jjg@659: jjg@659: // Cache for tool classes. jjg@659: // Use weak references to avoid keeping classes around unnecessarily jjg@659: private Map>> toolClasses = new HashMap>>(); jjg@659: jjg@659: // Cache for tool classloader. jjg@659: // Use a weak reference to avoid keeping it around unnecessarily jjg@659: private Reference refToolClassLoader = null; jjg@659: jjg@659: jjg@659: private ToolProvider() { } jjg@659: jjg@659: private T getSystemTool(Class clazz, String name) { jjg@659: Class c = getSystemToolClass(clazz, name); jjg@659: try { jjg@659: return c.asSubclass(clazz).newInstance(); jjg@659: } catch (Throwable e) { jjg@659: trace(WARNING, e); jjg@659: return null; jjg@659: } jjg@659: } jjg@659: jjg@659: private Class getSystemToolClass(Class clazz, String name) { jjg@659: Reference> refClass = toolClasses.get(name); jjg@659: Class c = (refClass == null ? null : refClass.get()); jjg@659: if (c == null) { duke@1: try { jjg@659: c = findSystemToolClass(name); jjg@659: } catch (Throwable e) { jjg@659: return trace(WARNING, e); duke@1: } jjg@659: toolClasses.put(name, new WeakReference>(c)); jjg@659: } jjg@659: return c.asSubclass(clazz); jjg@659: } jjg@659: jjg@659: private static final String[] defaultToolsLocation = { "lib", "tools.jar" }; jjg@659: jjg@659: private Class findSystemToolClass(String toolClassName) jjg@659: throws MalformedURLException, ClassNotFoundException jjg@659: { jjg@659: // try loading class directly, in case tool is on the bootclasspath jjg@659: try { jjg@816: return Class.forName(toolClassName, false, null); jjg@659: } catch (ClassNotFoundException e) { jjg@659: trace(FINE, e); jjg@659: jjg@659: // if tool not on bootclasspath, look in default tools location (tools.jar) jjg@659: ClassLoader cl = (refToolClassLoader == null ? null : refToolClassLoader.get()); jjg@659: if (cl == null) { jjg@659: File file = new File(System.getProperty("java.home")); jjg@659: if (file.getName().equalsIgnoreCase("jre")) jjg@659: file = file.getParentFile(); jjg@659: for (String name : defaultToolsLocation) jjg@659: file = new File(file, name); jjg@659: jjg@659: // if tools not found, no point in trying a URLClassLoader jjg@659: // so rethrow the original exception. jjg@659: if (!file.exists()) jjg@659: throw e; jjg@659: jjg@659: URL[] urls = { file.toURI().toURL() }; jjg@659: trace(FINE, urls[0].toString()); jjg@659: jjg@659: cl = URLClassLoader.newInstance(urls); jjg@659: refToolClassLoader = new WeakReference(cl); jjg@659: } jjg@659: jjg@659: return Class.forName(toolClassName, false, cl); duke@1: } jjg@659: } duke@1: }