ToolProvider.java revision 3294:9adfb22ff08f
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
26package javax.tools;
27
28import java.lang.reflect.InvocationTargetException;
29import java.lang.reflect.Method;
30import java.util.Iterator;
31import java.util.ServiceConfigurationError;
32import 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 */
42public 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&trade; 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                return Class.forName(className, true, ClassLoader.getSystemClassLoader()).asSubclass(clazz).newInstance();
127            } catch (ReflectiveOperationException e) {
128                throw new Error(e);
129            }
130        }
131
132        try {
133            ServiceLoader<T> sl = ServiceLoader.load(clazz, ClassLoader.getSystemClassLoader());
134            for (Iterator<T> iter = sl.iterator(); iter.hasNext(); ) {
135                T tool = iter.next();
136                if (matches(tool, moduleName))
137                    return tool;
138            }
139        } catch (ServiceConfigurationError e) {
140            throw new Error(e);
141        }
142        return null;
143    }
144
145    /**
146     * Determine if this is tho desired tool instance.
147     * @param <T>        the interface of the tool
148     * @param tool       the instance of the tool
149     * @param moduleName the name of the module containing the desired implementation
150     * @return true if and only if the tool matches the specified criteria
151     */
152    private static <T> boolean matches(T tool, String moduleName) {
153        // for now, use reflection to implement
154        //      return moduleName.equals(tool.getClass().getModule().getName());
155        try {
156            Method getModuleMethod = Class.class.getDeclaredMethod("getModule");
157            Object toolModule = getModuleMethod.invoke(tool.getClass());
158            Method getNameMethod = toolModule.getClass().getDeclaredMethod("getName");
159            String toolModuleName = (String) getNameMethod.invoke(toolModule);
160            return moduleName.equals(toolModuleName);
161        } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
162            return false;
163        }
164    }
165}
166