1 /* 2 * Copyright (c) 2005, 2016, 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.reflect.InvocationTargetException; 29 import java.lang.reflect.Method; 30 import java.util.Iterator; 31 import java.util.ServiceConfigurationError; 32 import java.util.ServiceLoader; 33 34 /** 35 * Provides methods for locating tool providers, for example, 36 * providers of compilers. This class complements the 37 * functionality of {@link java.util.ServiceLoader}. 38 * 39 * @author Peter von der Ahé 40 * @since 1.6 41 */ 42 public class ToolProvider { 43 44 private static final String systemJavaCompilerModule = "jdk.compiler"; 45 private static final String systemJavaCompilerName = "com.sun.tools.javac.api.JavacTool"; 46 47 /** 48 * Returns the Java™ programming language compiler provided 49 * with this platform. 50 * <p>The file manager returned by calling 51 * {@link JavaCompiler#getStandardFileManager getStandardFileManager} 52 * on this compiler supports paths provided by any 53 * {@linkplain java.nio.file.FileSystem filesystem}.</p> 54 * @return the compiler provided with this platform or 55 * {@code null} if no compiler is provided 56 * @implNote This implementation returns the compiler provided 57 * by the {@code jdk.compiler} module if that module is available, 58 * and null otherwise. 59 */ 60 public static JavaCompiler getSystemJavaCompiler() { 61 return getSystemTool(JavaCompiler.class, 62 systemJavaCompilerModule, systemJavaCompilerName); 63 } 64 65 private static final String systemDocumentationToolModule = "jdk.javadoc"; 66 private static final String systemDocumentationToolName = "jdk.javadoc.internal.api.JavadocTool"; 67 68 /** 69 * Returns the Java™ programming language documentation tool provided 70 * with this platform. 71 * <p>The file manager returned by calling 72 * {@link DocumentationTool#getStandardFileManager getStandardFileManager} 73 * on this tool supports paths provided by any 74 * {@linkplain java.nio.file.FileSystem filesystem}.</p> 75 * @return the documentation tool provided with this platform or 76 * {@code null} if no documentation tool is provided 77 * @implNote This implementation returns the tool provided 78 * by the {@code jdk.javadoc} module if that module is available, 79 * and null otherwise. 80 */ 81 public static DocumentationTool getSystemDocumentationTool() { 82 return getSystemTool(DocumentationTool.class, 83 systemDocumentationToolModule, systemDocumentationToolName); 84 } 85 86 /** 87 * Returns the class loader for tools provided with this platform. 88 * This does not include user-installed tools. Use the 89 * {@linkplain java.util.ServiceLoader service provider mechanism} 90 * for locating user installed tools. 91 * 92 * @return the class loader for tools provided with this platform 93 * or {@code null} if no tools are provided 94 */ 95 public static ClassLoader getSystemToolClassLoader() { 96 return ClassLoader.getSystemClassLoader(); 97 } 98 99 private static final boolean useLegacy; 100 101 static { 102 Class<?> c = null; 103 try { 104 c = Class.forName("java.lang.reflect.Module"); 105 } catch (Throwable t) { 106 } 107 useLegacy = (c == null); 108 } 109 110 /** 111 * Get an instance of a system tool using the service loader. 112 * @implNote By default, this returns the implementation in the specified module. 113 * For limited backward compatibility, if this code is run on an older version 114 * of the Java platform that does not support modules, this method will 115 * try and create an instance of the named class. Note that implies the 116 * class must be available on the system class path. 117 * @param <T> the interface of the tool 118 * @param clazz the interface of the tool 119 * @param moduleName the name of the module containing the desired implementation 120 * @param className the class name of the desired implementation 121 * @return the specified implementation of the tool 122 */ 123 private static <T> T getSystemTool(Class<T> clazz, String moduleName, String className) { 124 if (useLegacy) { 125 try { 126 @SuppressWarnings("deprecation") 127 T result = Class.forName(className, true, ClassLoader.getSystemClassLoader()).asSubclass(clazz).newInstance(); 128 return result; 129 } catch (ReflectiveOperationException e) { 130 throw new Error(e); 131 } 132 } 133 134 try { 135 ServiceLoader<T> sl = ServiceLoader.load(clazz, ClassLoader.getSystemClassLoader()); 136 for (Iterator<T> iter = sl.iterator(); iter.hasNext(); ) { 137 T tool = iter.next(); 138 if (matches(tool, moduleName)) 139 return tool; 140 } 141 } catch (ServiceConfigurationError e) { 142 throw new Error(e); 143 } 144 return null; 145 } 146 147 /** 148 * Determine if this is tho desired tool instance. 149 * @param <T> the interface of the tool 150 * @param tool the instance of the tool 151 * @param moduleName the name of the module containing the desired implementation 152 * @return true if and only if the tool matches the specified criteria 153 */ 154 private static <T> boolean matches(T tool, String moduleName) { 155 // for now, use reflection to implement 156 // return moduleName.equals(tool.getClass().getModule().getName()); 157 try { 158 Method getModuleMethod = Class.class.getDeclaredMethod("getModule"); 159 Object toolModule = getModuleMethod.invoke(tool.getClass()); 160 Method getNameMethod = toolModule.getClass().getDeclaredMethod("getName"); 161 String toolModuleName = (String) getNameMethod.invoke(toolModule); 162 return moduleName.equals(toolModuleName); 163 } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) { 164 return false; 165 } 166 } 167 }