diff options
author | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2013-02-26 09:45:40 +1100 |
---|---|---|
committer | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2013-02-26 09:45:40 +1100 |
commit | a285ee5bd7f796fde7ac2a4524d3789dc952ea73 (patch) | |
tree | 05528aea5d31eb96e915c8bd74ec072d6d16a7a9 | |
parent | 2a0cb4d76201ee1e6c9a879056e5ac0aea00a7b1 (diff) | |
download | classpath-a285ee5bd7f796fde7ac2a4524d3789dc952ea73.tar.gz |
Implement javax.tools.ToolProvider using ecj. Cleanup and make more use of Classpath logging mechanism.
Signed-off-by: Andrew John Hughes <gnu_andrew@member.fsf.org>
-rw-r--r-- | ChangeLog | 51 | ||||
-rw-r--r-- | gnu/classpath/ServiceFactory.java | 93 | ||||
-rw-r--r-- | gnu/classpath/debug/Component.java | 25 | ||||
-rw-r--r-- | gnu/classpath/debug/PreciseFilter.java | 14 | ||||
-rw-r--r-- | gnu/classpath/debug/SystemLogger.java | 61 | ||||
-rw-r--r-- | java/util/logging/Formatter.java | 2 | ||||
-rw-r--r-- | javax/tools/ToolProvider.java | 191 |
7 files changed, 361 insertions, 76 deletions
@@ -1,3 +1,54 @@ +2013-02-26 Andrew John Hughes <gnu_andrew@member.fsf.org> + + * gnu/classpath/ServiceFactory.java: + (LOGGER): Removed. + (lookupProviders(Class,ClassLoader,boolean)): + Use SystemLogger/Component mechanism for logging. + (ServiceIterator.loadNextServiceProvider()): + Likewise. Handle end-of-line comments as used + by ecj. + (advanceReader()): Use SystemLogger/Component + mechanism for logging. + (log(Component,Throwable,String,Object...)): + Change signature to use Component and take + a variable length series of Objects. Call + SystemLogger instance rather than using + local logging. + * gnu/classpath/debug/Component.java: + (EVERYTHING): Extend range to include new components. + (SSL_HANDSHAKE): Avoid spaces in name and change to + match variable name for lookup. + (SSL_RECORD_LAYER): Likewise. + (SSL_KEY_EXCHANGE): Likewise. + (SSL_DELEGATED_TASK): Likewise. + (SERVICE_LOADING): New component for ServiceFactory. + (SERVICE_LOADING_WARNING): Likewise. + (SERVICE_LOADING_VERBOSE): Likewise. + * gnu/classpath/debug/PreciseFilter.java: + (isLoggable(LogRecord)): Use instanceof rather + than triggering a ClassCastException and the whole + exception throwing mechanism. + * gnu/classpath/debug/SystemLogger.java: + (static): Fully initialise logger so all selection + is handled by the filter. + (logp(Component,String,String,Throwable,String,Object...)): + Adapted from log method in ServiceFactory. Handles + logging with both a Throwable and our own message. + * java/util/logging/Formatter.java: + Correct comment typo. + * javax/tools/ToolProvider.java: + Implemented. + (compiler): New field. + (COMPILER_CLASS): New constant field. + (getSystemJavaCompiler()): Return ecj if available. + (getSystemToolClassLoader()): Return classloader used + to load compiler. + (getCompilerClass()): Assistance method for finding + the compiler class. + (log(Component,Throwable,String,Object...)): + Logging method to auto-include the source class/method used + locally. + 2013-02-21 Andrew John Hughes <gnu_andrew@member.fsf.org> * javax/annotation/processing/AbstractProcessor.java: diff --git a/gnu/classpath/ServiceFactory.java b/gnu/classpath/ServiceFactory.java index f41d8e191..b167700f6 100644 --- a/gnu/classpath/ServiceFactory.java +++ b/gnu/classpath/ServiceFactory.java @@ -38,6 +38,12 @@ exception statement from your version. */ package gnu.classpath; +import static gnu.classpath.debug.Component.SERVICE_LOADING_VERBOSE; +import static gnu.classpath.debug.Component.SERVICE_LOADING_WARNING; +import static gnu.classpath.debug.SystemLogger.SYSTEM; + +import gnu.classpath.debug.Component; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -51,10 +57,6 @@ import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.ServiceConfigurationError; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; - /** * A factory for plug-ins that conform to a service provider @@ -168,15 +170,6 @@ import java.util.logging.Logger; */ public final class ServiceFactory { - /** - * A logger that gets informed when a service gets loaded, or - * when there is a problem with loading a service. - * - * <p>Because {@link java.util.logging.Logger#getLogger(String)} - * is thread-safe, we do not need to worry about synchronization - * here. - */ - private static final Logger LOGGER = Logger.getLogger("gnu.classpath"); /** * Declared private in order to prevent constructing instances of @@ -291,7 +284,7 @@ public final class ServiceFactory * providers. In this case, we simply return an iterator that * does not return anything (no providers installed). */ - log(Level.WARNING, "cannot access {0}", resourceName, ioex); + log(SERVICE_LOADING_WARNING, ioex, "cannot access {0}", resourceName); if (error) throw new ServiceConfigurationError("Failed to access + " + resourceName, ioex); @@ -486,8 +479,8 @@ public final class ServiceFactory } catch (IOException readProblem) { - log(Level.WARNING, "IOException upon reading {0}", currentURL, - readProblem); + log(SERVICE_LOADING_WARNING, readProblem, + "IOException upon reading {0}", currentURL); line = null; if (error) throw new ServiceConfigurationError("Error reading " + @@ -503,6 +496,10 @@ public final class ServiceFactory continue; } + // Trim comments from end of life. + int hashIndex = line.indexOf('#'); + if (hashIndex != -1) + line = line.substring(0, hashIndex); // Skip whitespace at the beginning and end of each line. line = line.trim(); @@ -517,11 +514,10 @@ public final class ServiceFactory try { - log(Level.FINE, + log(SERVICE_LOADING_VERBOSE, null, "Loading service provider \"{0}\", specified" + " by \"META-INF/services/{1}\" in {2}.", - new Object[] { line, spi.getName(), currentURL }, - null); + line, spi.getName(), currentURL); /* Load the class in the security context that was * active when calling lookupProviders. @@ -540,9 +536,8 @@ public final class ServiceFactory + " of \"{1}\". Specified" + " by \"META-INF/services/{1}\" in {2}."; - log(Level.WARNING, msg, - new Object[] { line, spi.getName(), currentURL }, - ex); + log(SERVICE_LOADING_WARNING, ex, + msg, line, spi.getName(), currentURL); if (error) throw new ServiceConfigurationError("Cannot load service "+ "provider class " + @@ -565,11 +560,11 @@ public final class ServiceFactory try { reader.close(); - log(Level.FINE, "closed {0}", currentURL, null); + log(SERVICE_LOADING_VERBOSE, null, "closed {0}", currentURL); } catch (Exception ex) { - log(Level.WARNING, "cannot close {0}", currentURL, ex); + log(SERVICE_LOADING_WARNING, ex, "cannot close {0}", currentURL); if (error) throw new ServiceConfigurationError("Cannot close " + currentURL, ex); @@ -586,11 +581,11 @@ public final class ServiceFactory { reader = new BufferedReader(new InputStreamReader( currentURL.openStream(), "UTF-8")); - log(Level.FINE, "opened {0}", currentURL, null); + log(SERVICE_LOADING_VERBOSE, null, "opened {0}", currentURL); } catch (Exception ex) { - log(Level.WARNING, "cannot open {0}", currentURL, ex); + log(SERVICE_LOADING_WARNING, ex, "cannot open {0}", currentURL); if (error) throw new ServiceConfigurationError("Cannot open " + currentURL, ex); @@ -600,54 +595,28 @@ public final class ServiceFactory } } - - // Package-private to avoid a trampoline. /** * Passes a log message to the <code>java.util.logging</code> * framework. This call returns very quickly if no log message will * be produced, so there is not much overhead in the standard case. * * @param level the severity of the message, for instance {@link - * Level#WARNING}. - * + * Component#SERVICE_LOGGING_WARNING}. + * @param t a Throwable that is associated with the log record, or + * <code>null</code> if the log message is not associated with a + * Throwable. * @param msg the log message, for instance <code>“Could not - * load {0}.”</code> - * - * @param param the parameter(s) for the log message, or + * load {0}.”</code> + * @param params the parameter(s) for the log message, or * <code>null</code> if <code>msg</code> does not specify any * parameters. If <code>param</code> is not an array, an array with * <code>param</code> as its single element gets passed to the * logging framework. - * - * @param t a Throwable that is associated with the log record, or - * <code>null</code> if the log message is not associated with a - * Throwable. */ - static void log(Level level, String msg, Object param, Throwable t) + static void log(Component level, Throwable t, String msg, Object... params) { - LogRecord rec; - - // Return quickly if no log message will be produced. - if (!LOGGER.isLoggable(level)) - return; - - rec = new LogRecord(level, msg); - if (param != null && param.getClass().isArray()) - rec.setParameters((Object[]) param); - else - rec.setParameters(new Object[] { param }); - - rec.setThrown(t); - - // While java.util.logging can sometimes infer the class and - // method of the caller, this automatic inference is not reliable - // on highly optimizing VMs. Also, log messages make more sense to - // developers when they display a public method in a public class; - // otherwise, they might feel tempted to figure out the internals - // of ServiceFactory in order to understand the problem. - rec.setSourceClassName(ServiceFactory.class.getName()); - rec.setSourceMethodName("lookupProviders"); - - LOGGER.log(rec); + SYSTEM.logp(level, ServiceFactory.class.getName(), "lookupProviders", + t, msg, params); } + } diff --git a/gnu/classpath/debug/Component.java b/gnu/classpath/debug/Component.java index 3cad8a2a7..eb841f441 100644 --- a/gnu/classpath/debug/Component.java +++ b/gnu/classpath/debug/Component.java @@ -74,7 +74,7 @@ public final class Component extends Level * Signifies that everything should be logged. This should be used to * enable or disable levels only; logging code should not use it. */ - public static final Component EVERYTHING = new Component ("*", 0, 11); + public static final Component EVERYTHING = new Component ("*", 0, 13); /** * Signifies that all SSL related messages should be logged. This should @@ -86,22 +86,22 @@ public final class Component extends Level /** * Traces the progression of an SSL handshake. */ - public static final Component SSL_HANDSHAKE = new Component ("SSL HANDSHAKE", 0); + public static final Component SSL_HANDSHAKE = new Component ("SSL_HANDSHAKE", 0); /** * Traces record layer messages during SSL communications. */ - public static final Component SSL_RECORD_LAYER = new Component ("SSL RECORD LAYER", 1); + public static final Component SSL_RECORD_LAYER = new Component ("SSL_RECORD_LAYER", 1); /** * Trace details about the SSL key exchange. */ - public static final Component SSL_KEY_EXCHANGE = new Component ("SSL KEY EXCHANGE", 2); + public static final Component SSL_KEY_EXCHANGE = new Component ("SSL_KEY_EXCHANGE", 2); /** * Trace running of delegated tasks. */ - public static final Component SSL_DELEGATED_TASK = new Component ("SSL DELEGATED TASK", 3); + public static final Component SSL_DELEGATED_TASK = new Component ("SSL_DELEGATED_TASK", 3); /* Index 4 reserved for future use by SSL components. */ @@ -126,6 +126,21 @@ public final class Component extends Level */ public static final Component IPP = new Component ("IPP", 10); + /** + * Service loading. + */ + public static final Component SERVICE_LOADING = new Component("SERVICE_LOADING", 11, 13); + + /** + * Service loading warnings. + */ + public static final Component SERVICE_LOADING_WARNING = new Component("SERVICE_LOADING_WARNING", 11); + + /** + * Service loading verbose messages. + */ + public static final Component SERVICE_LOADING_VERBOSE = new Component("SERVICE_LOADING_VERBOSE ", 12); + private final int startIndex; private final int endIndex; diff --git a/gnu/classpath/debug/PreciseFilter.java b/gnu/classpath/debug/PreciseFilter.java index 91f5a9e6c..cfce6130d 100644 --- a/gnu/classpath/debug/PreciseFilter.java +++ b/gnu/classpath/debug/PreciseFilter.java @@ -40,6 +40,7 @@ package gnu.classpath.debug; import java.util.BitSet; import java.util.logging.Filter; +import java.util.logging.Level; import java.util.logging.LogRecord; public final class PreciseFilter implements Filter @@ -93,13 +94,10 @@ public final class PreciseFilter implements Filter public boolean isLoggable (final LogRecord record) { - try - { - return isEnabled ((Component) record.getLevel ()); - } - catch (ClassCastException cce) - { - return true; - } + Level level = record.getLevel(); + if (level instanceof Component) + return isEnabled ((Component) level); + return true; } + } diff --git a/gnu/classpath/debug/SystemLogger.java b/gnu/classpath/debug/SystemLogger.java index eaca0fe98..d0587c055 100644 --- a/gnu/classpath/debug/SystemLogger.java +++ b/gnu/classpath/debug/SystemLogger.java @@ -41,9 +41,14 @@ package gnu.classpath.debug; import gnu.java.security.action.GetPropertyAction; import java.security.AccessController; + import java.util.StringTokenizer; + +import java.util.logging.ConsoleHandler; +import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.logging.LogRecord; public final class SystemLogger extends Logger { @@ -51,7 +56,13 @@ public final class SystemLogger extends Logger static { + SYSTEM.setLevel (Level.FINE); // So selection is left to filter SYSTEM.setFilter (PreciseFilter.GLOBAL); + Handler handler = new ConsoleHandler(); + handler.setLevel(Level.FINE); + handler.setFilter(PreciseFilter.GLOBAL); + SYSTEM.addHandler(handler); + SYSTEM.setUseParentHandlers(false); String defaults = (String) AccessController.doPrivileged (new GetPropertyAction("gnu.classpath.debug.components")); @@ -99,4 +110,54 @@ public final class SystemLogger extends Logger { log(level, format, args); } + + /** + * Passes a log message to the <code>java.util.logging</code> + * framework. This call returns very quickly if no log message will + * be produced, so there is not much overhead in the standard case. + * + * @param level the severity of the message, for instance {@link + * Component#SERVICE_LOGGING_WARNING}. + * @param sourceClass the name of the class that issued the logging + * request. + * @param sourceMethod the name of the method that issued the logging + * request. + * @param t a Throwable that is associated with the log record, or + * <code>null</code> if the log message is not associated with a + * Throwable. + * @param msg the log message, for instance <code>“Could not + * load {0}.”</code> + * @param params the parameter(s) for the log message, or + * <code>null</code> if <code>msg</code> does not specify any + * parameters. If <code>param</code> is not an array, an array with + * <code>param</code> as its single element gets passed to the + * logging framework. + */ + public void logp(Component level, String sourceClass, String sourceMethod, + Throwable t, String msg, Object... params) + { + LogRecord rec; + + // Return quickly if no log message will be produced. + if (!PreciseFilter.GLOBAL.isEnabled(level)) + return; + + rec = new LogRecord(level, msg); + if (params != null) + rec.setParameters(params); + + rec.setThrown(t); + + // While java.util.logging can sometimes infer the class and + // method of the caller, this automatic inference is not reliable + // on highly optimizing VMs. Also, log messages make more sense to + // developers when they display a public method in a public class; + // otherwise, they might feel tempted to figure out the internals + // in order to understand the problem. + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + + log(rec); + } + } diff --git a/java/util/logging/Formatter.java b/java/util/logging/Formatter.java index feaf55315..f4e4d013f 100644 --- a/java/util/logging/Formatter.java +++ b/java/util/logging/Formatter.java @@ -139,7 +139,7 @@ public abstract class Formatter ResourceBundle bundle; Object[] params; - /* This will throw a NullPointerExceptionif record is null. */ + /* This will throw a NullPointerException if record is null. */ msg = record.getMessage(); if (msg == null) msg = ""; diff --git a/javax/tools/ToolProvider.java b/javax/tools/ToolProvider.java new file mode 100644 index 000000000..3d16238b6 --- /dev/null +++ b/javax/tools/ToolProvider.java @@ -0,0 +1,191 @@ +/* ToolProvider.java -- Provides methods for obtaining tool implementations. + Copyright (C) 2013 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.tools; + +import gnu.classpath.Configuration; + +import static gnu.classpath.debug.Component.SERVICE_LOADING_VERBOSE; +import static gnu.classpath.debug.Component.SERVICE_LOADING_WARNING; +import static gnu.classpath.debug.SystemLogger.SYSTEM; + +import gnu.classpath.debug.Component; + +import java.io.File; + +import java.lang.reflect.InvocationTargetException; + +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * Provides methods for obtaining tool implementations. + * This complements the functionality provided by + * {@link ServiceLoader}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.6 + */ +public class ToolProvider +{ + + /** The system compiler if available. */ + private static JavaCompiler compiler; + + /** The class that implements the system compiler. */ + private static final String COMPILER_CLASS = + "org.eclipse.jdt.internal.compiler.tool.EclipseCompiler"; + + /** + * Returns the system Java compiler. This does not take + * account of compilers provided through the service + * loader functionality. + * + * @return the system compiler or {@code null} if one is not + * provided. + */ + public static synchronized JavaCompiler getSystemJavaCompiler() + { + if (compiler == null) + { + Class<?> compilerClass = getCompilerClass(); + if (compilerClass != null) + try + { + compiler = (JavaCompiler) + compilerClass.getConstructor().newInstance(); + } + catch (NoSuchMethodException e) + { + log(SERVICE_LOADING_WARNING, e, + "Couldn't find compiler constructor"); + } + catch (InstantiationException e) + { + log(SERVICE_LOADING_WARNING, e, + "Couldn't run compiler constructor"); + } + catch (IllegalAccessException e) + { + log(SERVICE_LOADING_WARNING, e, + "Couldn't access compiler constructor"); + } + catch (InvocationTargetException e) + { + log(SERVICE_LOADING_WARNING, e, + "Exception running compiler constructor"); + } + } + return compiler; + } + + /** + * Returns the class loader used to load system tools. + * + * @return the tool class loader or {@code null} if no + * tools are provided. + */ + public static synchronized ClassLoader getSystemToolClassLoader() + { + if (compiler != null) + return compiler.getClass().getClassLoader(); + return null; + } + + private static Class<?> getCompilerClass() + { + Class<?> compilerClass = null; + try + { + compilerClass = Class.forName(COMPILER_CLASS); + } + catch (ClassNotFoundException ex) + { + log(SERVICE_LOADING_VERBOSE, ex, + "Couldn''t find {0} on classpath", + COMPILER_CLASS); + + File jar = new File(Configuration.ECJ_JAR); + if (jar.exists() && jar.canRead()) + { + try + { + ClassLoader loader = + new URLClassLoader(new URL[] { jar.toURL() }); + compilerClass = loader.loadClass(COMPILER_CLASS); + } + catch (MalformedURLException e) + { + log(SERVICE_LOADING_WARNING, e, + "Bad ecj JAR URL: {0}", jar); + } + catch (ClassNotFoundException e) + { + log(SERVICE_LOADING_VERBOSE, e, + "Couldn''t find {0} in ecj jar", COMPILER_CLASS); + } + } + } + return compilerClass; + } + + /** + * Passes a log message to the <code>java.util.logging</code> + * framework. This call returns very quickly if no log message will + * be produced, so there is not much overhead in the standard case. + * + * @param level the severity of the message, for instance {@link + * Component#SERVICE_LOGGING_WARNING}. + * @param t a Throwable that is associated with the log record, or + * <code>null</code> if the log message is not associated with a + * Throwable. + * @param msg the log message, for instance <code>“Could not + * load {0}.”</code> + * @param params the parameter(s) for the log message, or + * <code>null</code> if <code>msg</code> does not specify any + * parameters. If <code>param</code> is not an array, an array with + * <code>param</code> as its single element gets passed to the + * logging framework. + */ + private static void log(Component level, Throwable t, String msg, Object... params) + { + SYSTEM.logp(level, ToolProvider.class.getName(), "getSystemJavaCompiler", + t, msg, params); + } + +} |