summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew John Hughes <gnu_andrew@member.fsf.org>2013-02-26 09:45:40 +1100
committerAndrew John Hughes <gnu_andrew@member.fsf.org>2013-02-26 09:45:40 +1100
commita285ee5bd7f796fde7ac2a4524d3789dc952ea73 (patch)
tree05528aea5d31eb96e915c8bd74ec072d6d16a7a9
parent2a0cb4d76201ee1e6c9a879056e5ac0aea00a7b1 (diff)
downloadclasspath-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--ChangeLog51
-rw-r--r--gnu/classpath/ServiceFactory.java93
-rw-r--r--gnu/classpath/debug/Component.java25
-rw-r--r--gnu/classpath/debug/PreciseFilter.java14
-rw-r--r--gnu/classpath/debug/SystemLogger.java61
-rw-r--r--java/util/logging/Formatter.java2
-rw-r--r--javax/tools/ToolProvider.java191
7 files changed, 361 insertions, 76 deletions
diff --git a/ChangeLog b/ChangeLog
index fe04fe283..d878e3822 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>&#x201c;Could not
- * load {0}.&#x201d;</code>
- *
- * @param param the parameter(s) for the log message, or
+ * load {0}.&#x201d;</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>&#x201c;Could not
+ * load {0}.&#x201d;</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>&#x201c;Could not
+ * load {0}.&#x201d;</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);
+ }
+
+}