6604599: ToolProvider should be less compiler-specific

Thu, 26 Aug 2010 15:17:17 -0700

author
jjg
date
Thu, 26 Aug 2010 15:17:17 -0700
changeset 659
cfd047f3cf60
parent 658
ecff24121064
child 660
ae3acbf63943

6604599: ToolProvider should be less compiler-specific
Reviewed-by: darcy

src/share/classes/javax/tools/ToolProvider.java file | annotate | diff | comparison | revisions
test/tools/javac/api/ToolProvider/HelloWorldTest.java file | annotate | diff | comparison | revisions
test/tools/javac/api/ToolProvider/ToolProviderTest1.java file | annotate | diff | comparison | revisions
test/tools/javac/api/ToolProvider/ToolProviderTest2.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/javax/tools/ToolProvider.java	Wed Aug 25 15:31:46 2010 -0700
     1.2 +++ b/src/share/classes/javax/tools/ToolProvider.java	Thu Aug 26 15:17:17 2010 -0700
     1.3 @@ -26,10 +26,14 @@
     1.4  package javax.tools;
     1.5  
     1.6  import java.io.File;
     1.7 +import java.lang.ref.Reference;
     1.8 +import java.lang.ref.WeakReference;
     1.9  import java.net.URL;
    1.10  import java.net.URLClassLoader;
    1.11  import java.net.MalformedURLException;
    1.12 +import java.util.HashMap;
    1.13  import java.util.Locale;
    1.14 +import java.util.Map;
    1.15  import java.util.logging.Logger;
    1.16  import java.util.logging.Level;
    1.17  import static java.util.logging.Level.*;
    1.18 @@ -44,8 +48,6 @@
    1.19   */
    1.20  public class ToolProvider {
    1.21  
    1.22 -    private ToolProvider() {}
    1.23 -
    1.24      private static final String propertyName = "sun.tools.ToolProvider";
    1.25      private static final String loggerName   = "javax.tools";
    1.26  
    1.27 @@ -87,6 +89,9 @@
    1.28          return null;
    1.29      }
    1.30  
    1.31 +    private static final String defaultJavaCompilerName
    1.32 +        = "com.sun.tools.javac.api.JavacTool";
    1.33 +
    1.34      /**
    1.35       * Gets the Java™ programming language compiler provided
    1.36       * with this platform.
    1.37 @@ -94,13 +99,7 @@
    1.38       * {@code null} if no compiler is provided
    1.39       */
    1.40      public static JavaCompiler getSystemJavaCompiler() {
    1.41 -        if (Lazy.compilerClass == null)
    1.42 -            return trace(WARNING, "Lazy.compilerClass == null");
    1.43 -        try {
    1.44 -            return Lazy.compilerClass.newInstance();
    1.45 -        } catch (Throwable e) {
    1.46 -            return trace(WARNING, e);
    1.47 -        }
    1.48 +        return instance().getSystemTool(JavaCompiler.class, defaultJavaCompilerName);
    1.49      }
    1.50  
    1.51      /**
    1.52 @@ -113,63 +112,109 @@
    1.53       * or {@code null} if no tools are provided
    1.54       */
    1.55      public static ClassLoader getSystemToolClassLoader() {
    1.56 -        if (Lazy.compilerClass == null)
    1.57 -            return trace(WARNING, "Lazy.compilerClass == null");
    1.58 -        return Lazy.compilerClass.getClassLoader();
    1.59 +        try {
    1.60 +            Class<? extends JavaCompiler> c =
    1.61 +                    instance().getSystemToolClass(JavaCompiler.class, defaultJavaCompilerName);
    1.62 +            return c.getClassLoader();
    1.63 +        } catch (Throwable e) {
    1.64 +            return trace(WARNING, e);
    1.65 +        }
    1.66      }
    1.67  
    1.68 -    /**
    1.69 -     * This class will not be initialized until one of the above
    1.70 -     * methods are called.  This ensures that searching for the
    1.71 -     * compiler does not affect platform start up.
    1.72 -     */
    1.73 -    static class Lazy  {
    1.74 -        private static final String defaultJavaCompilerName
    1.75 -            = "com.sun.tools.javac.api.JavacTool";
    1.76 -        private static final String[] defaultToolsLocation
    1.77 -            = { "lib", "tools.jar" };
    1.78 -        static final Class<? extends JavaCompiler> compilerClass;
    1.79 -        static {
    1.80 -            Class<? extends JavaCompiler> c = null;
    1.81 +
    1.82 +    private static ToolProvider instance;
    1.83 +
    1.84 +    private static synchronized ToolProvider instance() {
    1.85 +        if (instance == null)
    1.86 +            instance = new ToolProvider();
    1.87 +        return instance;
    1.88 +    }
    1.89 +
    1.90 +    // Cache for tool classes.
    1.91 +    // Use weak references to avoid keeping classes around unnecessarily
    1.92 +    private Map<String, Reference<Class<?>>> toolClasses = new HashMap<String, Reference<Class<?>>>();
    1.93 +
    1.94 +    // Cache for tool classloader.
    1.95 +    // Use a weak reference to avoid keeping it around unnecessarily
    1.96 +    private Reference<ClassLoader> refToolClassLoader = null;
    1.97 +
    1.98 +
    1.99 +    private ToolProvider() { }
   1.100 +
   1.101 +    private <T> T getSystemTool(Class<T> clazz, String name) {
   1.102 +        Class<? extends T> c = getSystemToolClass(clazz, name);
   1.103 +        try {
   1.104 +            return c.asSubclass(clazz).newInstance();
   1.105 +        } catch (Throwable e) {
   1.106 +            trace(WARNING, e);
   1.107 +            return null;
   1.108 +        }
   1.109 +    }
   1.110 +
   1.111 +    private <T> Class<? extends T> getSystemToolClass(Class<T> clazz, String name) {
   1.112 +        Reference<Class<?>> refClass = toolClasses.get(name);
   1.113 +        Class<?> c = (refClass == null ? null : refClass.get());
   1.114 +        if (c == null) {
   1.115              try {
   1.116 -                c = findClass().asSubclass(JavaCompiler.class);
   1.117 -            } catch (Throwable t) {
   1.118 -                trace(WARNING, t);
   1.119 +                c = findSystemToolClass(name);
   1.120 +            } catch (Throwable e) {
   1.121 +                return trace(WARNING, e);
   1.122              }
   1.123 -            compilerClass = c;
   1.124 +            toolClasses.put(name, new WeakReference<Class<?>>(c));
   1.125 +        }
   1.126 +        return c.asSubclass(clazz);
   1.127 +    }
   1.128 +
   1.129 +    private static final String[] defaultToolsLocation = { "lib", "tools.jar" };
   1.130 +
   1.131 +    private Class<?> findSystemToolClass(String toolClassName)
   1.132 +        throws MalformedURLException, ClassNotFoundException
   1.133 +    {
   1.134 +        // try loading class directly, in case tool is on the bootclasspath
   1.135 +        try {
   1.136 +            return enableAsserts(Class.forName(toolClassName, false, null));
   1.137 +        } catch (ClassNotFoundException e) {
   1.138 +            trace(FINE, e);
   1.139 +
   1.140 +            // if tool not on bootclasspath, look in default tools location (tools.jar)
   1.141 +            ClassLoader cl = (refToolClassLoader == null ? null : refToolClassLoader.get());
   1.142 +            if (cl == null) {
   1.143 +                File file = new File(System.getProperty("java.home"));
   1.144 +                if (file.getName().equalsIgnoreCase("jre"))
   1.145 +                    file = file.getParentFile();
   1.146 +                for (String name : defaultToolsLocation)
   1.147 +                    file = new File(file, name);
   1.148 +
   1.149 +                // if tools not found, no point in trying a URLClassLoader
   1.150 +                // so rethrow the original exception.
   1.151 +                if (!file.exists())
   1.152 +                    throw e;
   1.153 +
   1.154 +                URL[] urls = { file.toURI().toURL() };
   1.155 +                trace(FINE, urls[0].toString());
   1.156 +
   1.157 +                cl = URLClassLoader.newInstance(urls);
   1.158 +                cl.setPackageAssertionStatus("com.sun.tools.javac", true);
   1.159 +                refToolClassLoader = new WeakReference<ClassLoader>(cl);
   1.160 +            }
   1.161 +
   1.162 +            return Class.forName(toolClassName, false, cl);
   1.163          }
   1.164  
   1.165 -        private static Class<?> findClass()
   1.166 -            throws MalformedURLException, ClassNotFoundException
   1.167 -        {
   1.168 -            try {
   1.169 -                return enableAsserts(Class.forName(defaultJavaCompilerName, false, null));
   1.170 -            } catch (ClassNotFoundException e) {
   1.171 -                trace(FINE, e);
   1.172 -            }
   1.173 -            File file = new File(System.getProperty("java.home"));
   1.174 -            if (file.getName().equalsIgnoreCase("jre"))
   1.175 -                file = file.getParentFile();
   1.176 -            for (String name : defaultToolsLocation)
   1.177 -                file = new File(file, name);
   1.178 -            URL[] urls = {file.toURI().toURL()};
   1.179 -            trace(FINE, urls[0].toString());
   1.180 -            ClassLoader cl = URLClassLoader.newInstance(urls);
   1.181 -            cl.setPackageAssertionStatus("com.sun.tools.javac", true);
   1.182 -            return Class.forName(defaultJavaCompilerName, false, cl);
   1.183 +    }
   1.184 +
   1.185 +    private static Class<?> enableAsserts(Class<?> cls) {
   1.186 +        try {
   1.187 +            ClassLoader loader = cls.getClassLoader();
   1.188 +            if (loader != null)
   1.189 +                loader.setPackageAssertionStatus("com.sun.tools.javac", true);
   1.190 +            else
   1.191 +                trace(FINE, "loader == null");
   1.192 +        } catch (SecurityException ex) {
   1.193 +            trace(FINE, ex);
   1.194          }
   1.195 +        return cls;
   1.196 +    }
   1.197  
   1.198 -        private static Class<?> enableAsserts(Class<?> cls) {
   1.199 -            try {
   1.200 -                ClassLoader loader = cls.getClassLoader();
   1.201 -                if (loader != null)
   1.202 -                    loader.setPackageAssertionStatus("com.sun.tools.javac", true);
   1.203 -                else
   1.204 -                    trace(FINE, "loader == null");
   1.205 -            } catch (SecurityException ex) {
   1.206 -                trace(FINE, ex);
   1.207 -            }
   1.208 -            return cls;
   1.209 -        }
   1.210 -    }
   1.211 +
   1.212  }
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/tools/javac/api/ToolProvider/HelloWorldTest.java	Thu Aug 26 15:17:17 2010 -0700
     2.3 @@ -0,0 +1,83 @@
     2.4 +/*
     2.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
     2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.7 + *
     2.8 + * This code is free software; you can redistribute it and/or modify it
     2.9 + * under the terms of the GNU General Public License version 2 only, as
    2.10 + * published by the Free Software Foundation.
    2.11 + *
    2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.15 + * version 2 for more details (a copy is included in the LICENSE file that
    2.16 + * accompanied this code).
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License version
    2.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.21 + *
    2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    2.23 + * or visit www.oracle.com if you need additional information or have any
    2.24 + * questions.
    2.25 + */
    2.26 +
    2.27 +/*
    2.28 + * @test
    2.29 + * @bug 6604599
    2.30 + * @summary ToolProvider should be less compiler-specific
    2.31 + */
    2.32 +
    2.33 +import java.io.*;
    2.34 +import java.util.*;
    2.35 +
    2.36 +// verify that running a simple program, such as this one, does not trigger
    2.37 +// the loading of ToolProvider or any com.sun.tools.javac class
    2.38 +public class HelloWorldTest {
    2.39 +    public static void main(String... args) throws Exception {
    2.40 +        if (args.length > 0) {
    2.41 +            System.err.println(Arrays.asList(args));
    2.42 +            return;
    2.43 +        }
    2.44 +
    2.45 +        new HelloWorldTest().run();
    2.46 +    }
    2.47 +
    2.48 +    void run() throws Exception {
    2.49 +        File javaHome = new File(System.getProperty("java.home"));
    2.50 +        if (javaHome.getName().equals("jre"))
    2.51 +            javaHome = javaHome.getParentFile();
    2.52 +        File javaExe = new File(new File(javaHome, "bin"), "java");
    2.53 +        String classpath = System.getProperty("java.class.path");
    2.54 +
    2.55 +        String[] cmd = {
    2.56 +            javaExe.getPath(),
    2.57 +            "-verbose:class",
    2.58 +            "-classpath", classpath,
    2.59 +            HelloWorldTest.class.getName(),
    2.60 +            "Hello", "World"
    2.61 +        };
    2.62 +
    2.63 +        ProcessBuilder pb = new ProcessBuilder(cmd).redirectErrorStream(true);
    2.64 +        Process p = pb.start();
    2.65 +        BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
    2.66 +        String line;
    2.67 +        while ((line = r.readLine()) != null) {
    2.68 +            System.err.println(line);
    2.69 +            if (line.contains("javax.tools.ToolProvider") || line.contains("com.sun.tools.javac."))
    2.70 +                error(">>> " + line);
    2.71 +        }
    2.72 +        int rc = p.waitFor();
    2.73 +        if (rc != 0)
    2.74 +            error("Unexpected exit code: " + rc);
    2.75 +
    2.76 +        if (errors > 0)
    2.77 +            throw new Exception(errors + " errors occurred");
    2.78 +    }
    2.79 +
    2.80 +    void error(String msg) {
    2.81 +        System.err.println(msg);
    2.82 +        errors++;
    2.83 +    }
    2.84 +
    2.85 +    int errors;
    2.86 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/test/tools/javac/api/ToolProvider/ToolProviderTest1.java	Thu Aug 26 15:17:17 2010 -0700
     3.3 @@ -0,0 +1,82 @@
     3.4 +/*
     3.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.
    3.11 + *
    3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.15 + * version 2 for more details (a copy is included in the LICENSE file that
    3.16 + * accompanied this code).
    3.17 + *
    3.18 + * You should have received a copy of the GNU General Public License version
    3.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.21 + *
    3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    3.23 + * or visit www.oracle.com if you need additional information or have any
    3.24 + * questions.
    3.25 + */
    3.26 +
    3.27 +/*
    3.28 + * @test
    3.29 + * @bug 6604599
    3.30 + * @summary ToolProvider should be less compiler-specific
    3.31 + */
    3.32 +
    3.33 +import java.io.*;
    3.34 +
    3.35 +// verify that running accessing ToolProvider by itself does not
    3.36 +// trigger loading com.sun.tools.javac.*
    3.37 +public class ToolProviderTest1 {
    3.38 +    public static void main(String... args) throws Exception {
    3.39 +        if (args.length > 0) {
    3.40 +            System.err.println(Class.forName(args[0], true, null));
    3.41 +            return;
    3.42 +        }
    3.43 +
    3.44 +        new ToolProviderTest1().run();
    3.45 +    }
    3.46 +
    3.47 +    void run() throws Exception {
    3.48 +        File javaHome = new File(System.getProperty("java.home"));
    3.49 +        if (javaHome.getName().equals("jre"))
    3.50 +            javaHome = javaHome.getParentFile();
    3.51 +        File javaExe = new File(new File(javaHome, "bin"), "java");
    3.52 +        String classpath = System.getProperty("java.class.path");
    3.53 +
    3.54 +        String[] cmd = {
    3.55 +            javaExe.getPath(),
    3.56 +            "-verbose:class",
    3.57 +            "-classpath", classpath,
    3.58 +            ToolProviderTest1.class.getName(),
    3.59 +            "javax.tools.ToolProvider"
    3.60 +        };
    3.61 +
    3.62 +        ProcessBuilder pb = new ProcessBuilder(cmd).redirectErrorStream(true);
    3.63 +        Process p = pb.start();
    3.64 +        BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
    3.65 +        String line;
    3.66 +        while ((line = r.readLine()) != null) {
    3.67 +            System.err.println(line);
    3.68 +            if (line.contains("com.sun.tools.javac."))
    3.69 +                error(">>> " + line);
    3.70 +        }
    3.71 +        int rc = p.waitFor();
    3.72 +        if (rc != 0)
    3.73 +            error("Unexpected exit code: " + rc);
    3.74 +
    3.75 +        if (errors > 0)
    3.76 +            throw new Exception(errors + " errors occurred");
    3.77 +    }
    3.78 +
    3.79 +    void error(String msg) {
    3.80 +        System.err.println(msg);
    3.81 +        errors++;
    3.82 +    }
    3.83 +
    3.84 +    int errors;
    3.85 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/tools/javac/api/ToolProvider/ToolProviderTest2.java	Thu Aug 26 15:17:17 2010 -0700
     4.3 @@ -0,0 +1,87 @@
     4.4 +/*
     4.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
     4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.7 + *
     4.8 + * This code is free software; you can redistribute it and/or modify it
     4.9 + * under the terms of the GNU General Public License version 2 only, as
    4.10 + * published by the Free Software Foundation.
    4.11 + *
    4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    4.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    4.15 + * version 2 for more details (a copy is included in the LICENSE file that
    4.16 + * accompanied this code).
    4.17 + *
    4.18 + * You should have received a copy of the GNU General Public License version
    4.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    4.21 + *
    4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    4.23 + * or visit www.oracle.com if you need additional information or have any
    4.24 + * questions.
    4.25 + */
    4.26 +
    4.27 +/*
    4.28 + * @test
    4.29 + * @bug 6604599
    4.30 + * @summary ToolProvider should be less compiler-specific
    4.31 + */
    4.32 +
    4.33 +import java.io.*;
    4.34 +import javax.tools.*;
    4.35 +
    4.36 +// control for ToolProviderTest1 -- verify that using ToolProvider to
    4.37 +// access the compiler does trigger loading com.sun.tools.javac.*
    4.38 +public class ToolProviderTest2 {
    4.39 +    public static void main(String... args) throws Exception {
    4.40 +        if (args.length > 0) {
    4.41 +            System.err.println(ToolProvider.getSystemJavaCompiler());
    4.42 +            return;
    4.43 +        }
    4.44 +
    4.45 +        new ToolProviderTest2().run();
    4.46 +    }
    4.47 +
    4.48 +    void run() throws Exception {
    4.49 +        File javaHome = new File(System.getProperty("java.home"));
    4.50 +        if (javaHome.getName().equals("jre"))
    4.51 +            javaHome = javaHome.getParentFile();
    4.52 +        File javaExe = new File(new File(javaHome, "bin"), "java");
    4.53 +        String classpath = System.getProperty("java.class.path");
    4.54 +
    4.55 +        String[] cmd = {
    4.56 +            javaExe.getPath(),
    4.57 +            "-verbose:class",
    4.58 +            "-classpath", classpath,
    4.59 +            ToolProviderTest2.class.getName(),
    4.60 +            "javax.tools.ToolProvider"
    4.61 +        };
    4.62 +
    4.63 +        ProcessBuilder pb = new ProcessBuilder(cmd).redirectErrorStream(true);
    4.64 +        Process p = pb.start();
    4.65 +        BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
    4.66 +        String line;
    4.67 +        boolean found = false;
    4.68 +        while ((line = r.readLine()) != null) {
    4.69 +            System.err.println(line);
    4.70 +            if (line.contains("com.sun.tools.javac."))
    4.71 +                found = true;
    4.72 +        }
    4.73 +        int rc = p.waitFor();
    4.74 +        if (rc != 0)
    4.75 +            error("Unexpected exit code: " + rc);
    4.76 +
    4.77 +        if (!found)
    4.78 +            System.err.println("expected class name not found");
    4.79 +
    4.80 +        if (errors > 0)
    4.81 +            throw new Exception(errors + " errors occurred");
    4.82 +    }
    4.83 +
    4.84 +    void error(String msg) {
    4.85 +        System.err.println(msg);
    4.86 +        errors++;
    4.87 +    }
    4.88 +
    4.89 +    int errors;
    4.90 +}

mercurial