001    /*
002     * Copyright 2005-2006 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package javax.tools;
027    
028    import java.io.File;
029    import java.net.URL;
030    import java.net.URLClassLoader;
031    import java.net.MalformedURLException;
032    import java.util.Locale;
033    import java.util.logging.Logger;
034    import java.util.logging.Level;
035    import static java.util.logging.Level.*;
036    
037    /**
038     * Provides methods for locating tool providers, for example,
039     * providers of compilers.  This class complements the
040     * functionality of {@link java.util.ServiceLoader}.
041     *
042     * @author Peter von der Ahé
043     * @since 1.6
044     */
045    public class ToolProvider {
046    
047        private ToolProvider() {}
048    
049        private static final String propertyName = "sun.tools.ToolProvider";
050        private static final String loggerName   = "javax.tools";
051    
052        /*
053         * Define the system property "sun.tools.ToolProvider" to enable
054         * debugging:
055         *
056         *     java ... -Dsun.tools.ToolProvider ...
057         */
058        static <T> T trace(Level level, Object reason) {
059            // NOTE: do not make this method private as it affects stack traces
060            try {
061                if (System.getProperty(propertyName) != null) {
062                    StackTraceElement[] st = Thread.currentThread().getStackTrace();
063                    String method = "???";
064                    String cls = ToolProvider.class.getName();
065                    if (st.length > 2) {
066                        StackTraceElement frame = st[2];
067                        method = String.format((Locale)null, "%s(%s:%s)",
068                                               frame.getMethodName(),
069                                               frame.getFileName(),
070                                               frame.getLineNumber());
071                        cls = frame.getClassName();
072                    }
073                    Logger logger = Logger.getLogger(loggerName);
074                    if (reason instanceof Throwable) {
075                        logger.logp(level, cls, method,
076                                    reason.getClass().getName(), (Throwable)reason);
077                    } else {
078                        logger.logp(level, cls, method, String.valueOf(reason));
079                    }
080                }
081            } catch (SecurityException ex) {
082                System.err.format((Locale)null, "%s: %s; %s%n",
083                                  ToolProvider.class.getName(),
084                                  reason,
085                                  ex.getLocalizedMessage());
086            }
087            return null;
088        }
089    
090        /**
091         * Gets the Java&trade; programming language compiler provided
092         * with this platform.
093         * @return the compiler provided with this platform or
094         * {@code null} if no compiler is provided
095         */
096        public static JavaCompiler getSystemJavaCompiler() {
097            if (Lazy.compilerClass == null)
098                return trace(WARNING, "Lazy.compilerClass == null");
099            try {
100                return Lazy.compilerClass.newInstance();
101            } catch (Throwable e) {
102                return trace(WARNING, e);
103            }
104        }
105    
106        /**
107         * Returns the class loader for tools provided with this platform.
108         * This does not include user-installed tools.  Use the
109         * {@linkplain java.util.ServiceLoader service provider mechanism}
110         * for locating user installed tools.
111         *
112         * @return the class loader for tools provided with this platform
113         * or {@code null} if no tools are provided
114         */
115        public static ClassLoader getSystemToolClassLoader() {
116            if (Lazy.compilerClass == null)
117                return trace(WARNING, "Lazy.compilerClass == null");
118            return Lazy.compilerClass.getClassLoader();
119        }
120    
121        /**
122         * This class will not be initialized until one of the above
123         * methods are called.  This ensures that searching for the
124         * compiler does not affect platform start up.
125         */
126        static class Lazy  {
127            private static final String defaultJavaCompilerName
128                = "com.sun.tools.javac.api.JavacTool";
129            private static final String[] defaultToolsLocation
130                = { "lib", "tools.jar" };
131            static final Class<? extends JavaCompiler> compilerClass;
132            static {
133                Class<? extends JavaCompiler> c = null;
134                try {
135                    c = findClass().asSubclass(JavaCompiler.class);
136                } catch (Throwable t) {
137                    trace(WARNING, t);
138                }
139                compilerClass = c;
140            }
141    
142            private static Class<?> findClass()
143                throws MalformedURLException, ClassNotFoundException
144            {
145                try {
146                    return enableAsserts(Class.forName(defaultJavaCompilerName, false, null));
147                } catch (ClassNotFoundException e) {
148                    trace(FINE, e);
149                }
150                File file = new File(System.getProperty("java.home"));
151                if (file.getName().equalsIgnoreCase("jre"))
152                    file = file.getParentFile();
153                for (String name : defaultToolsLocation)
154                    file = new File(file, name);
155                URL[] urls = {file.toURI().toURL()};
156                trace(FINE, urls[0].toString());
157                ClassLoader cl = URLClassLoader.newInstance(urls);
158                cl.setPackageAssertionStatus("com.sun.tools.javac", true);
159                return Class.forName(defaultJavaCompilerName, false, cl);
160            }
161    
162            private static Class<?> enableAsserts(Class<?> cls) {
163                try {
164                    ClassLoader loader = cls.getClassLoader();
165                    if (loader != null)
166                        loader.setPackageAssertionStatus("com.sun.tools.javac", true);
167                    else
168                        trace(FINE, "loader == null");
169                } catch (SecurityException ex) {
170                    trace(FINE, ex);
171                }
172                return cls;
173            }
174        }
175    }