1 /* 2 * Copyright (c) 2005, 2015, 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.lang.ref.Reference; 29 import java.lang.ref.WeakReference; 30 import java.util.HashMap; 31 import java.util.Locale; 32 import java.util.Map; 33 import java.util.logging.Logger; 34 import java.util.logging.Level; 35 36 import static java.util.logging.Level.*; 37 38 /** 39 * Provides methods for locating tool providers, for example, 40 * providers of compilers. This class complements the 41 * functionality of {@link java.util.ServiceLoader}. 42 * 43 * @author Peter von der Ahé 44 * @since 1.6 45 */ 46 public class ToolProvider { 47 48 private static final String propertyName = "sun.tools.ToolProvider"; 49 private static final String loggerName = "javax.tools"; 50 51 /* 52 * Define the system property "sun.tools.ToolProvider" to enable 53 * debugging: 54 * 55 * java ... -Dsun.tools.ToolProvider ... 56 */ 57 static <T> T trace(Level level, Object reason) { 58 // NOTE: do not make this method private as it affects stack traces 59 try { 60 if (System.getProperty(propertyName) != null) { 61 StackTraceElement[] st = Thread.currentThread().getStackTrace(); 62 String method = "???"; 63 String cls = ToolProvider.class.getName(); 64 if (st.length > 2) { 65 StackTraceElement frame = st[2]; 66 method = String.format((Locale)null, "%s(%s:%s)", 67 frame.getMethodName(), 68 frame.getFileName(), 69 frame.getLineNumber()); 70 cls = frame.getClassName(); 71 } 72 Logger logger = Logger.getLogger(loggerName); 73 if (reason instanceof Throwable) { 74 logger.logp(level, cls, method, 75 reason.getClass().getName(), (Throwable)reason); 76 } else { 77 logger.logp(level, cls, method, String.valueOf(reason)); 78 } 79 } 80 } catch (SecurityException ex) { 81 System.err.format((Locale)null, "%s: %s; %s%n", 82 ToolProvider.class.getName(), 83 reason, 84 ex.getLocalizedMessage()); 85 } 86 return null; 87 } 88 89 private static final String systemJavaCompilerName 90 = "com.sun.tools.javac.api.JavacTool"; 91 92 /** 93 * Returns the Java™ programming language compiler provided 94 * with this platform. 95 * <p>The file manager returned by calling 96 * {@link JavaCompiler#getStandardFileManager getStandardFileManager} 97 * on this compiler supports paths provided by any 98 * {@linkplain java.nio.file.FileSystem filesystem}.</p> 99 * @return the compiler provided with this platform or 100 * {@code null} if no compiler is provided 101 */ 102 public static JavaCompiler getSystemJavaCompiler() { 103 return instance().getSystemTool(JavaCompiler.class, systemJavaCompilerName); 104 } 105 106 private static final String systemDocumentationToolName 107 = "com.sun.tools.javadoc.api.JavadocTool"; 108 109 /** 110 * Returns the Java™ programming language documentation tool provided 111 * with this platform. 112 * <p>The file manager returned by calling 113 * {@link DocumentationTool#getStandardFileManager getStandardFileManager} 114 * on this tool supports paths provided by any 115 * {@linkplain java.nio.file.FileSystem filesystem}.</p> 116 * @return the documentation tool provided with this platform or 117 * {@code null} if no documentation tool is provided 118 */ 119 public static DocumentationTool getSystemDocumentationTool() { 120 return instance().getSystemTool(DocumentationTool.class, systemDocumentationToolName); 121 } 122 123 /** 124 * Returns the class loader for tools provided with this platform. 125 * This does not include user-installed tools. Use the 126 * {@linkplain java.util.ServiceLoader service provider mechanism} 127 * for locating user installed tools. 128 * 129 * @return the class loader for tools provided with this platform 130 * or {@code null} if no tools are provided 131 */ 132 public static ClassLoader getSystemToolClassLoader() { 133 return ClassLoader.getSystemClassLoader(); 134 } 135 136 137 private static ToolProvider instance; 138 139 private static synchronized ToolProvider instance() { 140 if (instance == null) 141 instance = new ToolProvider(); 142 return instance; 143 } 144 145 // Cache for tool classes. 146 // Use weak references to avoid keeping classes around unnecessarily 147 private final Map<String, Reference<Class<?>>> toolClasses = new HashMap<>(); 148 149 private ToolProvider() { } 150 151 private <T> T getSystemTool(Class<T> clazz, String name) { 152 Class<? extends T> c = getSystemToolClass(clazz, name); 153 try { 154 return c.asSubclass(clazz).newInstance(); 155 } catch (InstantiationException | IllegalAccessException | RuntimeException | Error e) { 156 return trace(WARNING, e); 157 } 158 } 159 160 private <T> Class<? extends T> getSystemToolClass(Class<T> clazz, String name) { 161 Reference<Class<?>> refClass = toolClasses.get(name); 162 Class<?> c = (refClass == null ? null : refClass.get()); 163 if (c == null) { 164 try { 165 c = Class.forName(name, false, ClassLoader.getSystemClassLoader()); 166 } catch (ClassNotFoundException | RuntimeException | Error e) { 167 return trace(WARNING, e); 168 } 169 toolClasses.put(name, new WeakReference<>(c)); 170 } 171 return c.asSubclass(clazz); 172 } 173 }