--- old/jdk/src/java.base/share/classes/java/lang/System.java 2015-10-09 21:41:50.000000000 +0200
+++ new/jdk/src/java.base/share/classes/java/lang/System.java 2015-10-09 21:41:50.000000000 +0200
@@ -30,13 +30,19 @@
import java.security.AccessControlContext;
import java.util.Properties;
import java.util.PropertyPermission;
-import java.util.StringTokenizer;
import java.util.Map;
import java.security.AccessController;
import java.security.PrivilegedAction;
-import java.security.AllPermission;
import java.nio.channels.Channel;
import java.nio.channels.spi.SelectorProvider;
+import java.util.Objects;
+import java.util.ResourceBundle;
+import java.security.Permission;
+import java.util.Arrays;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+import java.util.function.Supplier;
+import sun.util.logger.JdkLoggerProvider;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
@@ -45,6 +51,9 @@
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.misc.JavaLangAccess;;
import jdk.internal.misc.SharedSecrets;;
+import sun.util.logger.BootstrapLogger;
+import sun.util.logger.LazyLoggers;
+import sun.util.logger.LocalizedLoggerWrapper;
/**
* The System
class contains several useful class fields
@@ -944,6 +953,822 @@
}
/**
+ * The minimum set of methods that a logger returned by the
+ * {@link LoggerFinder} service should implement.
+ * Instances of loggers implementing this interface are obtained from
+ * the {@link java.lang.System System} class, by calling
+ * {@link java.lang.System#getLogger(java.lang.String) System.getLogger(loggerName)}
+ * or {@link java.lang.System#getLogger(java.lang.String, java.util.ResourceBundle)
+ * System.getLogger(loggerName, bundle)}.
+ *
+ * Unless + * + * @see java.lang.System + * @see java.lang.System.LoggerFinder + * + * @since 9 + * + */ + public interface Logger { + + /** + * Message levels for the {@link Logger loggers} + * returned by the {@link LoggerFinder} service. + *
+ * A level has a {@linkplain #getName() name} and {@linkplain
+ * #getSeverity() severity}.
+ * Standard level values are {@link #ALL}, {@link #TRACE}, {@link #DEBUG},
+ * {@link #INFO}, {@link #WARNING}, {@link #ERROR}, {@link #OFF},
+ * by order of increasing severity.
+ *
+ * {@link #ALL} and {@link #OFF}
+ * are simple markers with severities mapped respectively to
+ * {@link java.lang.Integer#MIN_VALUE Integer.MIN_VALUE} and
+ * {@link java.lang.Integer#MAX_VALUE Integer.MAX_VALUE}.
+ *
+ * For convenience the severity values are mapped to corresponding
+ * {@link java.util.logging.Level java.util.logging.Level} severity
+ * values.
+ *
+ * @since 9
+ *
+ * @see java.lang.System.LoggerFinder
+ * @see java.lang.System.Logger
+ */
+ public enum Level {
+
+ // for convenience, we're reusing java.util.logging.Level int values
+ // the mapping logic in sun.util.logging.PlatformLogger depends
+ // on this.
+ /**
+ * A marker to indicate that all levels are enabled.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@link Integer#MIN_VALUE}.
+ */
+ ALL(Integer.MIN_VALUE), // usually mapped to/from j.u.l.Level.ALL
+ /**
+ * {@code TRACE} level: usually used to log diagnostic information.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 400}.
+ */
+ TRACE(400), // usually mapped to/from j.u.l.Level.FINER
+ /**
+ * {@code DEBUG} level: usually used to log debug information traces.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 500}.
+ */
+ DEBUG(500), // usually mapped to/from j.u.l.Level.FINEST/FINE/CONFIG
+ /**
+ * {@code INFO} level: usually used to log information messages.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 800}.
+ */
+ INFO(800), // usually mapped to/from j.u.l.Level.INFO
+ /**
+ * {@code WARNING} level: usually used to log warning messages.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 900}.
+ */
+ WARNING(900), // usually mapped to/from j.u.l.Level.WARNING
+ /**
+ * {@code ERROR} level: usually used to log error messages.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@code 1000}.
+ */
+ ERROR(1000), // usually mapped to/from j.u.l.Level.SEVERE
+ /**
+ * A marker to indicate that all levels are disabled.
+ * This level {@linkplain #getSeverity() severity} is
+ * {@link Integer#MAX_VALUE}.
+ */
+ OFF(Integer.MAX_VALUE); // usually mapped to/from j.u.l.Level.OFF
+
+ private final int severity;
+
+ private Level(int severity) {
+ this.severity = severity;
+ }
+
+ /**
+ * Returns the name of this level.
+ * @return this level {@linkplain #name()}.
+ */
+ public final String getName() {
+ return name();
+ }
+
+ /**
+ * Returns the severity of this level.
+ * A higher severity means a more severe condition.
+ * @return this level severity.
+ */
+ public final int getSeverity() {
+ return severity;
+ }
+ }
+
+ /**
+ * Returns the name of this logger.
+ *
+ * @return the logger name.
+ */
+ public String getName();
+
+ /**
+ * Checks if a message of the given level would be logged by
+ * this logger.
+ *
+ * @param level the message level.
+ * @return {@code true} if the given message level is currently being logged.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public boolean isLoggable(Level level);
+
+ /**
+ * Logs a message.
+ *
+ * @implSpec The default implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msg, (Object[])null);}
+ *
+ * @param level the message level.
+ * @param msg the string message (or a key in the message catalog, if
+ * this logger is a {@link
+ * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class)
+ * localized logger}).
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public default void log(Level level, String msg) {
+ log(level, (ResourceBundle) null, msg, (Object[]) null);
+ }
+
+ /**
+ * Logs a lazily supplied message.
+ *
+ * If the logger is currently enabled for the given message level
+ * then a message is logged that is the result produced by the
+ * given supplier function. Otherwise, the supplier is not operated on.
+ *
+ * @implSpec When logging is enabled for the given level, the default
+ * implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msgSupplier.get(), (Object[])null);}
+ *
+ * @param level the message level.
+ * @param msgSupplier a supplier function that produces a message.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}, or if the level
+ * is loggable and {@code msgSupplier} is {@code null}.
+ */
+ public default void log(Level level, Supplier
+ * If the logger is currently enabled for the given message level then
+ * a message is logged that, by default, is the result produced from
+ * calling toString on the given object.
+ * Otherwise, the object is not operated on.
+ *
+ * @implSpec When logging is enabled for the given level, the default
+ * implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, obj.toString(), (Object[])null);}
+ *
+ * @param level the message level.
+ * @param obj the object to log.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}, or if the level
+ * is loggable and {@code obj} is {@code null}.
+ */
+ public default void log(Level level, Object obj) {
+ if (isLoggable(level)) {
+ this.log(level, (ResourceBundle) null, obj.toString(), (Object[]) null);
+ }
+ }
+
+ /**
+ * Logs a message associated with a given throwable.
+ *
+ * @implSpec The default implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msg, thrown);}
+ *
+ * @param level the message level.
+ * @param msg the string message (or a key in the message catalog, if
+ * this logger is a {@link
+ * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class)
+ * localized logger}).
+ * @param thrown a {@code Throwable} associated with the log message.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public default void log(Level level, String msg, Throwable thrown) {
+ this.log(level, null, msg, thrown);
+ }
+
+ /**
+ * Logs a lazily supplied message associated with a given throwable.
+ *
+ * If the logger is currently enabled for the given message level
+ * then a message is logged that is the result produced by the
+ * given supplier function. Otherwise, the supplier is not operated on.
+ *
+ * @implSpec When logging is enabled for the given level, the default
+ * implementation for this method calls
+ * {@code this.log(level, (ResourceBundle)null, msgSupplier.get(), thrown);}
+ *
+ * @param level one of the message level identifiers.
+ * @param msgSupplier a supplier function that produces a message.
+ * @param thrown a {@code Throwable} associated with log message.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}, or if the level
+ * is loggable and {@code msgSupplier} is {@code null}.
+ */
+ public default void log(Level level, Supplier
+ * If the given resource bundle is non-{@code null}, the {@code msg}
+ * string is localized using the given resource bundle.
+ * Otherwise the {@code msg} string is not localized.
+ *
+ * @param level the message level.
+ * @param bundle a resource bundle to localize {@code msg}, can be
+ * {@code null}.
+ * @param msg the string message (or a key in the message catalog,
+ * if {@code bundle} is not {@code null}).
+ * @param thrown a {@code Throwable} associated with the log message.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public void log(Level level, ResourceBundle bundle, String msg,
+ Throwable thrown);
+
+ /**
+ * Logs a message with resource bundle and an optional list of
+ * parameters.
+ *
+ * If the given resource bundle is non-{@code null}, the {@code format}
+ * string is localized using the given resource bundle.
+ * Otherwise the {@code format} string is not localized.
+ *
+ * @param level the message level.
+ * @param bundle a resource bundle to localize {@code format}, can be
+ * {@code null}.
+ * @param format the string message format (or a key in the message
+ * catalog if {@code bundle} is not {@code null}).
+ * @param params an optional list of parameters to the message (may be
+ * none).
+ *
+ * @throws NullPointerException if {@code level} is {@code null}.
+ */
+ public void log(Level level, ResourceBundle bundle, String format,
+ Object... params);
+
+
+ }
+
+ /**
+ * The {@code LoggerFinder} service makes it possible to provide an
+ * alternate implementation for System.Loggers used in the JDK.
+ *
+ * Working with loggers obtained from the {@code LoggerFinder}
+ *
+ * The {@code LoggerFinder} class makes it possible to replace
+ * the logging backend through which logging events originating from
+ * platform classes will be routed. The backend of the default
+ * {@code LoggerFinder} implementation is still
+ * {@code java.util.logging}, but it can now be replaced by providing and
+ * declaring an alternate implementation of the {@code LoggerFinder}
+ * service.
+ *
+ * The JDK uses the {@link java.util.ServiceLoader}
+ * facility to locate and load a concrete implementation of the
+ * {@code LoggerFinder} service, from the {@linkplain
+ * java.lang.ClassLoader#getSystemClassLoader() System ClassLoader}.
+ * If no custom implementation is found the JDK will use its own default
+ * implementation. If more than one implementation is found, a
+ * {@link java.util.ServiceConfigurationError} will be thrown.
+ *
+ * Only one instance of the {@code LoggerFinder} implementation is created.
+ * That instance is responsible for creating, managing, and configuring
+ * loggers as appropriate to the underlying framework it is using.
+ *
+ * In the JDK, a platform class that needs to log messages will obtain
+ * a logger that will route messages to a {@link Logger Logger} instance
+ * obtained from one of the factory methods provided by the
+ * {@code LoggerFinder} implementation.
+ *
+ * {@link Logger Logger} instances obtained from the {@code
+ * LoggerFinder} factory methods are not directly configurable by
+ * the application. Configuration is the responsibility of the underlying
+ * logging backend, and usually requires using APIs specific to that
+ * backend.
+ *
+ * System loggers (loggers obtained on behalf of platform classes) are
+ * usually kept in a global logger tree which is separated from the
+ * application logger tree. It is the responsibility of the provider of
+ * the concrete {@code LoggerFinder} implementation to ensure that
+ * system loggers can not be configured by an application without proper
+ * permission checks, as configuration performed on system loggers usually
+ * affects all applications in the same Java Runtime.
+ *
+ * Default Implementation
+ *
+ * The JDK default implementation of the {@code LoggerFinder} service
+ * will attempt to bind to the {@linkplain java.util.logging java.logging}
+ * module.
+ * When the {@linkplain java.util.logging java.logging} module is present,
+ * the default implementation will return {@link Logger} instances wrapping
+ * instances of {@link java.util.logging.Logger java.util.logging.Logger}.
+ * In that case, configuration may be performed by direct access to the
+ * {@code java.util.logging} APIs, using {@link java.util.logging.Logger
+ * java.util.logging.Logger} and {@link java.util.logging.LogManager} to
+ * access and configure the backend loggers.
+ *
+ * Note that if an implementation of the {@code LoggerFinder} service
+ * interface has been found by the {@link java.util.ServiceLoader}, then
+ * the JDK default implementation of {@code LoggerFinder} is not used and
+ * configuration can only be performed through APIs provided by the backend
+ * framework which the custom implementation of {@code LoggerFinder} has
+ * plugged in.
+ *
+ * Note also that the {@linkplain java.util.logging java.logging} module
+ * does not directly provide an implementation of the {@code LoggerFinder}
+ * service. The JDK default concrete implementation of {@code LoggerFinder}
+ * use instead a JDK private API to bind to {@code java.util.logging}.
+ * This makes it possible for an application to replace the logging backend
+ * even when the java.logging module is present, by simply providing
+ * and declaring an implementation of the {@link LoggerFinder} service.
+ *
+ * Message Levels and Mapping to {@code java.util.logging}
+ *
+ * The {@link Logger.Level Logger.Level} enum defines
+ * a set of standard levels: {@link Logger.Level#ALL ALL},
+ * {@link Logger.Level#TRACE TRACE},
+ * {@link Logger.Level#DEBUG DEBUG},
+ * {@link Logger.Level#INFO INFO},
+ * {@link Logger.Level#WARNING WARNING},
+ * {@link Logger.Level#ERROR ERROR},
+ * and {@link Logger.Level#OFF OFF}, by order of increased severity.
+ *
+ * When the logging backend supports custom levels, how to map System.Logger
+ * levels to backend levels is the responsibility of the backend.
+ *
+ * When {@link java.util.logging} is the backend, System.Logger levels are
+ * mapped to {@linkplain java.util.logging.Level java.util.logging levels}
+ * as follows:
+ *
+ * Migrating From {@code java.util.logging}
+ *
+ * Usually - an application that uses a logging framework will log messages
+ * through a logger facade defined (or supported) by that framework.
+ * Applications that wish to use an external framework should log
+ * through the facade associated with that framework.
+ *
+ * Changing the {@code LoggerFinder} Implementation
+ *
+ * An application wishing to change the implementation of the
+ * {@code LoggerFinder} is expected to provide a concrete implementation
+ * of the {@code LoggerFinder} abstract class accessible from the
+ * {@linkplain java.lang.ClassLoader#getSystemClassLoader()
+ * System ClassLoader} and registered as a service in such a way that it
+ * can be located and loaded by the {@link java.util.ServiceLoader}.
+ * Note that because the loaded instance of {@code LoggerFinder} is
+ * global, it will be only looked for in the {@linkplain
+ * java.lang.ClassLoader#getSystemClassLoader() System ClassLoader} (and its
+ * parents).
+ *
+ *
+ * @see java.lang.System
+ * @see java.lang.System.Logger
+ *
+ * @since 9
+ */
+ public static abstract class LoggerFinder {
+ /**
+ * The {@code RuntimePermission("loggerFinder")} is
+ * necessary to subclass and instantiate the {@code LoggerFinder} class,
+ * as well as to obtain loggers from an instance of that class.
+ */
+ public static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+
+ /**
+ * Creates a new instance of {@code LoggerFinder}.
+ *
+ * Only one instance will be created.
+ *
+ * @implNote It is recommended that subclasses of {@code LoggerFinder}
+ * do not perform any heavy initialization in their constructor, in
+ * order to avoid possible risks of deadlock or class loading cycles
+ * during the instantiation of the provider.
+ *
+ * @throws SecurityException if the calling code does not have the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ protected LoggerFinder() {
+ this(checkPermission());
+ }
+
+ private LoggerFinder(Void unused) {
+ // nothing to do.
+ }
+
+ private static Void checkPermission() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ return null;
+ }
+
+ /**
+ * Returns an instance of {@link Logger Logger}
+ * suitable for the given caller.
+ *
+ * @param name the name of the logger.
+ * @param caller the class for which the logger is being requested.
+ *
+ * @return a {@link Logger logger} suitable for the given caller's
+ * use.
+ * @throws SecurityException if the calling code does not have the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public abstract Logger getLogger(String name, /* Module */ Class> caller);
+
+ /**
+ * Returns a localizable instance of {@link Logger Logger}
+ * suitable for the given caller.
+ * The returned logger will use the provided resource bundle for
+ * message localization.
+ *
+ * @implSpec By default, this method calls {@link
+ * #getLogger(java.lang.String, java.lang.Class)
+ * this.getLogger(name, caller)} to obtain a logger, then wraps that
+ * logger in a {@link Logger} instance where all methods that do not
+ * take a {@link ResourceBundle} as parameter are redirected to one
+ * which does - passing the given {@code bundle} for
+ * localization. So for instance, a call to {@link
+ * Logger#log(Level, String) Logger.log(Level.INFO, msg)}
+ * will end up as a call to {@link
+ * Logger#log(Level, ResourceBundle, String, Object...)
+ * Logger.log(Level.INFO, bundle, msg, (Object[])null)} on the wrapped
+ * logger object.
+ * Note however that by default, string messages returned by {@link
+ * java.util.function.Supplier Supplier<String>} will not be
+ * localized, as it is assumed that such strings are messages which are
+ * already constructed, rather than keys in a resource bundle.
+ *
+ * An implementation of {@code LoggerFinder} is not
+ * constrained to use the default implementation of this method. In
+ * particular, if the underlying logging backend provides its own
+ * mechanism for localizing log messages, then such a
+ * {@code LoggerFinder} would be free to return a logger
+ * that makes direct use of the mechanism provided by the backend.
+ *
+ * @param name the name of the logger.
+ * @param bundle a resource bundle.
+ * @param caller the class for which the logger is being requested.
+ * @return an instance of {@link Logger Logger} which will use the
+ * provided resource bundle for message localization.
+ *
+ * @throws SecurityException if the calling code does not have the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public Logger getLocalizedLogger(String name, ResourceBundle bundle,
+ /* Module */ Class> caller) {
+ return new LocalizedLoggerWrapper<>(getLogger(name, caller), bundle);
+ }
+
+ /**
+ * Returns the loaded {@link LoggerFinder LoggerFinder} instance.
+ * @return the loaded {@link LoggerFinder LoggerFinder} instance.
+ * @throws SecurityException if the calling code does not have the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public static LoggerFinder getLoggerFinder() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ return LoggerFinderLoader.spi();
+ }
+
+ /**
+ * Helper class used to load the {@link LoggerFinder}.
+ */
+ final static class LoggerFinderLoader {
+ private static volatile LoggerFinder spi;
+ private static final Object lock = new int[0];
+ static final Permission CLASSLOADER_PERMISSION =
+ SecurityConstants.GET_CLASSLOADER_PERMISSION;
+ static final Permission READ_PERMISSION =
+ new FilePermission("<
+ * By default, when {@link java.util.logging}
+ * is present, the {@code DefaultLoggerFinder} returns loggers that
+ * wrap {@link java.util.logging.Logger} created by the internal
+ * {@link sun.util.logging.internal.JdkLoggingProvider}.
+ * Backend loggers are obtained by
+ * calling {@link
+ * java.util.logging.LogManager#demandLoggerFor(java.lang.String, java.lang.Class)}.
+ * Backend loggers can be configured by direct
+ * use of the {@link java.util.logging} APIs.
+ *
+ * When {@link java.util.logging}
+ * is not present, the {@code DefaultLoggerFinder} returns
+ * {@linkplain sun.util.logger.SimpleConsoleLogger
+ * simple console loggers}.
+ * By default, only message of level {@code INFO} and above will be
+ * printed on the console.
+ * For compatibility reason system loggers can be configured by
+ * direct use of the internal {@code PlatformLogger} API.
+ * For application loggers however, there is no API that would allow
+ * the application to configure these loggers.
+ *
+ * Therefore an application that needs to configure loggers should
+ * either link with {@link java.util.logging} or install its own
+ * {@link LoggerFinder} service.
+ */
+ final static class DefaultLoggerFinder extends LoggerFinder {
+
+ // Default JdkLoggerProvider used when no JdkLoggerProvider is
+ // declared as an installed service.
+ static final class DefaultJdkLoggerProvider extends JdkLoggerProvider {
+ }
+
+ private static JdkLoggerProvider loadJdkLoggerProvider() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+
+ final ServiceLoader
+ * If the {@link java.util.logging java.logging} module is not linked
+ * with the application, and no service implementation for the
+ * {@code LoggerFinder} has been found, then the default implementation
+ * will return a simple logger that prints out all log messages of
+ * {@link java.lang.System.Logger.Level#INFO INFO}
+ * level and above to the console ({@code System.err}).
+ *
+ * These simple loggers are not configurable.
+ *
+ * Libraries and classes that only need loggers to produce log messages
+ * should therefore not attempt to configure loggers by themselves, as that
+ * would make them dependant from a specific implementation of the
+ * {@code LoggerFinder} service.
+ *
+ * {@link Logger.Level#ALL Level.ALL} and {@link Logger.Level#OFF Level.OFF}
+ * are simple markers with severities mapped respectively to
+ * {@link java.lang.Integer#MIN_VALUE Integer.MIN_VALUE} and
+ * {@link java.lang.Integer#MAX_VALUE Integer.MAX_VALUE}.
+ *
+ *
+ *
+ *
+ * System.Logger Levels
+ * {@link Logger.Level#ALL ALL}
+ * {@link Logger.Level#TRACE TRACE}
+ * {@link Logger.Level#DEBUG DEBUG}
+ * {@link Logger.Level#INFO INFO}
+ * {@link Logger.Level#WARNING WARNING}
+ * {@link Logger.Level#ERROR ERROR}
+ * {@link Logger.Level#OFF OFF}
+ *
+ * java.util.logging Backend
+ * {@link java.util.logging.Level#ALL ALL}
+ * {@link java.util.logging.Level#FINER FINER}
+ * {@link java.util.logging.Level#FINE FINE}
+ * {@link java.util.logging.Level#INFO INFO}
+ * {@link java.util.logging.Level#WARNING WARNING}
+ * {@link java.util.logging.Level#SEVERE SEVERE}
+ * {@link java.util.logging.Level#OFF OFF}
+ *