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&trade; 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         = "jdk.javadoc.internal.api.JavadocTool";
 108 
 109     /**
 110      * Returns the Java&trade; 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 }