Thu, 15 Nov 2012 23:07:24 -0800
6493690: javadoc should have a javax.tools.Tool service provider installed in tools.jar
Reviewed-by: darcy
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 */
26 package javax.tools;
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.*;
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 {
51 private static final String propertyName = "sun.tools.ToolProvider";
52 private static final String loggerName = "javax.tools";
54 /*
55 * Define the system property "sun.tools.ToolProvider" to enable
56 * debugging:
57 *
58 * java ... -Dsun.tools.ToolProvider ...
59 */
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 }
92 private static final String defaultJavaCompilerName
93 = "com.sun.tools.javac.api.JavacTool";
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 */
101 public static JavaCompiler getSystemJavaCompiler() {
102 return instance().getSystemTool(JavaCompiler.class, defaultJavaCompilerName);
103 }
105 private static final String defaultDocumentationToolName
106 = "com.sun.tools.javadoc.api.JavadocTool";
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 */
114 public static DocumentationTool getSystemDocumentationTool() {
115 return instance().getSystemTool(DocumentationTool.class, defaultDocumentationToolName);
116 }
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 */
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 }
138 private static ToolProvider instance;
140 private static synchronized ToolProvider instance() {
141 if (instance == null)
142 instance = new ToolProvider();
143 return instance;
144 }
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<?>>>();
150 // Cache for tool classloader.
151 // Use a weak reference to avoid keeping it around unnecessarily
152 private Reference<ClassLoader> refToolClassLoader = null;
155 private ToolProvider() { }
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 }
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 }
181 private static final String[] defaultToolsLocation = { "lib", "tools.jar" };
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);
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);
201 // if tools not found, no point in trying a URLClassLoader
202 // so rethrow the original exception.
203 if (!file.exists())
204 throw e;
206 URL[] urls = { file.toURI().toURL() };
207 trace(FINE, urls[0].toString());
209 cl = URLClassLoader.newInstance(urls);
210 refToolClassLoader = new WeakReference<ClassLoader>(cl);
211 }
213 return Class.forName(toolClassName, false, cl);
214 }
215 }
216 }