1 /* 2 * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.tools; 27 28 import java.io.File; 29 import java.lang.ref.Reference; 30 import java.lang.ref.WeakReference; 31 import java.net.URL; 32 import java.net.URLClassLoader; 33 import java.net.MalformedURLException; 34 import java.util.HashMap; 35 import java.util.Locale; 36 import java.util.Map; 37 import java.util.logging.Logger; 38 import java.util.logging.Level; 39 import static java.util.logging.Level.*; 40 41 /** 42 * Provides methods for locating tool providers, for example, 43 * providers of compilers. This class complements the 44 * functionality of {@link java.util.ServiceLoader}. 45 * 46 * @author Peter von der Ahé 47 * @since 1.6 48 */ 49 public class ToolProvider { 50 51 private static final String propertyName = "sun.tools.ToolProvider"; 52 private static final String loggerName = "javax.tools"; 53 54 /* 55 * Define the system property "sun.tools.ToolProvider" to enable 56 * debugging: 57 * 58 * java ... -Dsun.tools.ToolProvider ... 59 */ trace(Level level, Object reason)60 static <T> T trace(Level level, Object reason) { 61 // NOTE: do not make this method private as it affects stack traces 62 try { 63 if (System.getProperty(propertyName) != null) { 64 StackTraceElement[] st = Thread.currentThread().getStackTrace(); 65 String method = "???"; 66 String cls = ToolProvider.class.getName(); 67 if (st.length > 2) { 68 StackTraceElement frame = st[2]; 69 method = String.format((Locale)null, "%s(%s:%s)", 70 frame.getMethodName(), 71 frame.getFileName(), 72 frame.getLineNumber()); 73 cls = frame.getClassName(); 74 } 75 Logger logger = Logger.getLogger(loggerName); 76 if (reason instanceof Throwable) { 77 logger.logp(level, cls, method, 78 reason.getClass().getName(), (Throwable)reason); 79 } else { 80 logger.logp(level, cls, method, String.valueOf(reason)); 81 } 82 } 83 } catch (SecurityException ex) { 84 System.err.format((Locale)null, "%s: %s; %s%n", 85 ToolProvider.class.getName(), 86 reason, 87 ex.getLocalizedMessage()); 88 } 89 return null; 90 } 91 92 private static final String defaultJavaCompilerName 93 = "com.sun.tools.javac.api.JavacTool"; 94 95 /** 96 * Gets the Java™ programming language compiler provided 97 * with this platform. 98 * @return the compiler provided with this platform or 99 * {@code null} if no compiler is provided 100 */ getSystemJavaCompiler()101 public static JavaCompiler getSystemJavaCompiler() { 102 return instance().getSystemTool(JavaCompiler.class, defaultJavaCompilerName); 103 } 104 105 private static final String defaultDocumentationToolName 106 = "com.sun.tools.javadoc.api.JavadocTool"; 107 108 /** 109 * Gets the Java™ programming language documentation tool provided 110 * with this platform. 111 * @return the documentation tool provided with this platform or 112 * {@code null} if no documentation tool is provided 113 */ getSystemDocumentationTool()114 public static DocumentationTool getSystemDocumentationTool() { 115 return instance().getSystemTool(DocumentationTool.class, defaultDocumentationToolName); 116 } 117 118 /** 119 * Returns the class loader for tools provided with this platform. 120 * This does not include user-installed tools. Use the 121 * {@linkplain java.util.ServiceLoader service provider mechanism} 122 * for locating user installed tools. 123 * 124 * @return the class loader for tools provided with this platform 125 * or {@code null} if no tools are provided 126 */ getSystemToolClassLoader()127 public static ClassLoader getSystemToolClassLoader() { 128 try { 129 Class<? extends JavaCompiler> c = 130 instance().getSystemToolClass(JavaCompiler.class, defaultJavaCompilerName); 131 return c.getClassLoader(); 132 } catch (Throwable e) { 133 return trace(WARNING, e); 134 } 135 } 136 137 138 private static ToolProvider instance; 139 instance()140 private static synchronized ToolProvider instance() { 141 if (instance == null) 142 instance = new ToolProvider(); 143 return instance; 144 } 145 146 // Cache for tool classes. 147 // Use weak references to avoid keeping classes around unnecessarily 148 private Map<String, Reference<Class<?>>> toolClasses = new HashMap<String, Reference<Class<?>>>(); 149 150 // Cache for tool classloader. 151 // Use a weak reference to avoid keeping it around unnecessarily 152 private Reference<ClassLoader> refToolClassLoader = null; 153 154 ToolProvider()155 private ToolProvider() { } 156 getSystemTool(Class<T> clazz, String name)157 private <T> T getSystemTool(Class<T> clazz, String name) { 158 Class<? extends T> c = getSystemToolClass(clazz, name); 159 try { 160 return c.asSubclass(clazz).newInstance(); 161 } catch (Throwable e) { 162 trace(WARNING, e); 163 return null; 164 } 165 } 166 getSystemToolClass(Class<T> clazz, String name)167 private <T> Class<? extends T> getSystemToolClass(Class<T> clazz, String name) { 168 Reference<Class<?>> refClass = toolClasses.get(name); 169 Class<?> c = (refClass == null ? null : refClass.get()); 170 if (c == null) { 171 try { 172 c = findSystemToolClass(name); 173 } catch (Throwable e) { 174 return trace(WARNING, e); 175 } 176 toolClasses.put(name, new WeakReference<Class<?>>(c)); 177 } 178 return c.asSubclass(clazz); 179 } 180 181 private static final String[] defaultToolsLocation = { "lib", "tools.jar" }; 182 findSystemToolClass(String toolClassName)183 private Class<?> findSystemToolClass(String toolClassName) 184 throws MalformedURLException, ClassNotFoundException 185 { 186 // try loading class directly, in case tool is on the bootclasspath 187 try { 188 return Class.forName(toolClassName, false, null); 189 } catch (ClassNotFoundException e) { 190 trace(FINE, e); 191 192 // if tool not on bootclasspath, look in default tools location (tools.jar) 193 ClassLoader cl = (refToolClassLoader == null ? null : refToolClassLoader.get()); 194 if (cl == null) { 195 File file = new File(System.getProperty("java.home")); 196 if (file.getName().equalsIgnoreCase("jre")) 197 file = file.getParentFile(); 198 for (String name : defaultToolsLocation) 199 file = new File(file, name); 200 201 // if tools not found, no point in trying a URLClassLoader 202 // so rethrow the original exception. 203 if (!file.exists()) 204 throw e; 205 206 URL[] urls = { file.toURI().toURL() }; 207 trace(FINE, urls[0].toString()); 208 209 cl = URLClassLoader.newInstance(urls); 210 refToolClassLoader = new WeakReference<ClassLoader>(cl); 211 } 212 213 return Class.forName(toolClassName, false, cl); 214 } 215 } 216 } 217