--- old/jdk/src/java.base/share/classes/java/lang/System.java 2015-11-20 17:44:01.000000000 +0100
+++ new/jdk/src/java.base/share/classes/java/lang/System.java 2015-11-20 17:44:01.000000000 +0100
@@ -30,13 +30,14 @@
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.util.function.Supplier;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
@@ -45,6 +46,9 @@
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.misc.JavaLangAccess;;
import jdk.internal.misc.SharedSecrets;;
+import jdk.internal.logger.LoggerFinderLoader;
+import jdk.internal.logger.LazyLoggers;
+import jdk.internal.logger.LocalizedLoggerWrapper;
/**
* The System
class contains several useful class fields
@@ -944,6 +948,648 @@
}
/**
+ * {@code System.Logger} instances log messages that will be
+ * routed to the underlying logging framework the {@link System.LoggerFinder
+ * LoggerFinder} uses.
+ *
+ * {@code System.Logger} instances are typically 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)}. + * + * @see java.lang.System#getLogger(java.lang.String) + * @see java.lang.System#getLogger(java.lang.String, java.util.ResourceBundle) + * @see java.lang.System.LoggerFinder + * + * @since 9 + * + */ + public interface Logger { + + /** + * System {@linkplain Logger loggers} levels. + *
+ * A level has a {@linkplain #getName() name} and {@linkplain
+ * #getSeverity() severity}.
+ * 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}.
+ *
+ * Severity values and Mapping to {@code java.util.logging.Level}. + *
+ * {@linkplain System.Logger.Level System logger levels} are mapped to
+ * {@linkplain java.util.logging.Level java.util.logging levels}
+ * of corresponding severity.
+ *
The mapping is as follows:
+ *
+ *
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 Levels | + *{@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} | + *
+ * If the logger is currently enabled for the given log 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 log message level.
+ * @param msgSupplier a supplier function that produces a message.
+ *
+ * @throws NullPointerException if {@code level} is {@code null},
+ * or {@code msgSupplier} is {@code null}.
+ */
+ public default void log(Level level, Supplier
+ * If the logger is currently enabled for the given log 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 log message level.
+ * @param obj the object to log.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}, or
+ * {@code obj} is {@code null}.
+ */
+ public default void log(Level level, Object obj) {
+ Objects.requireNonNull(obj);
+ if (isLoggable(Objects.requireNonNull(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 log 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}); can be {@code null}.
+ * @param thrown a {@code Throwable} associated with the log message;
+ * can be {@code null}.
+ *
+ * @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 log 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 log message level identifiers.
+ * @param msgSupplier a supplier function that produces a message.
+ * @param thrown a {@code Throwable} associated with log message;
+ * can be {@code null}.
+ *
+ * @throws NullPointerException if {@code level} is {@code null}, or
+ * {@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 log 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}); can be {@code null}.
+ * @param thrown a {@code Throwable} associated with the log message;
+ * can be {@code null}.
+ *
+ * @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 log message level.
+ * @param bundle a resource bundle to localize {@code format}; can be
+ * {@code null}.
+ * @param format the string message format in {@link
+ * java.text.MessageFormat} format, (or a key in the message
+ * catalog if {@code bundle} is not {@code null}); can be {@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 is responsible for creating, managing,
+ * and configuring loggers to the underlying framework it uses.
+ *
+ * A logger finder is a concrete implementation of this class that has a
+ * zero-argument constructor and implements the abstract methods defined
+ * by this class.
+ * The loggers returned from a logger finder are capable of routing log
+ * messages to the logging backend this provider supports.
+ * A given invocation of the Java Runtime maintains a single
+ * system-wide LoggerFinder instance that is loaded as follows:
+ *
+ * An application can replace the logging backend
+ * even when the java.logging module is present, by simply providing
+ * and declaring an implementation of the {@link LoggerFinder} service.
+ *
+ * Default Implementation
+ *
+ * The system default {@code LoggerFinder} implementation uses
+ * {@code java.util.logging} as the backend framework when the
+ * {@code java.logging} module is present.
+ * It returns a {@linkplain System.Logger logger} instance
+ * that will route log messages to a {@link java.util.logging.Logger
+ * java.util.logging.Logger}. Otherwise, if {@code java.logging} is not
+ * present, the default implementation will return a simple logger
+ * instance that will route log messages of {@code INFO} level and above to
+ * the console ({@code System.err}).
+ *
+ * Logging Configuration
+ *
+ * {@linkplain 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.
+ * For the default {@code LoggerFinder} implementation
+ * using {@code java.util.logging} as its backend, refer to
+ * {@link java.util.logging java.util.logging} for logging configuration.
+ * For the default {@code LoggerFinder} implementation returning simple loggers
+ * when the {@code java.logging} module is absent, the configuration
+ * is implementation dependent.
+ *
+ * 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.
+ *
+ * A system class that needs to log messages will typically obtain
+ * a {@link System.Logger} instance to route messages to the logging
+ * framework selected by the application.
+ *
+ * Libraries and classes that only need loggers to produce log messages
+ * should not attempt to configure loggers by themselves, as that
+ * would make them dependent from a specific implementation of the
+ * {@code LoggerFinder} service.
+ *
+ * In addition, when a security manager is present, loggers provided to
+ * system classes should not be directly configurable through the logging
+ * backend without requiring permissions.
+ *
+ * Message Levels and Mapping to backend levels
+ *
+ * A logger finder is responsible for mapping from a {@code
+ * System.Logger.Level} to a level supported by the logging backend it uses.
+ *
+ * An implementation of {@code LoggerFinder} may override this method,
+ * for example, when 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; can be {@code null}.
+ * @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 NullPointerException if {@code name} is {@code null} or
+ * {@code caller} is {@code null}.
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public Logger getLocalizedLogger(String name, ResourceBundle bundle,
+ /* Module */ Class> caller) {
+ return new LocalizedLoggerWrapper<>(getLogger(name, caller), bundle);
+ }
+
+ /**
+ * Returns the {@code LoggerFinder} instance. There is one
+ * single system-wide {@code LoggerFinder} instance in
+ * the Java Runtime. See the class specification of how the
+ * {@link LoggerFinder LoggerFinder} implementation is located and
+ * loaded.
+
+ * @return the {@link LoggerFinder LoggerFinder} instance.
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public static LoggerFinder getLoggerFinder() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(LOGGERFINDER_PERMISSION);
+ }
+ return accessProvider();
+ }
+
+
+ private static volatile LoggerFinder service;
+ static LoggerFinder accessProvider() {
+ // We do not need to synchronize: LoggerFinderLoader will
+ // always return the same instance, so if we don't have it,
+ // just fetch it again.
+ if (service == null) {
+ PrivilegedAction
+ *
+ *
+ * It is the responsibility of the provider of
+ * the concrete {@code LoggerFinder} implementation to ensure that
+ * these loggers are not configured by untrusted code without proper
+ * permission checks, as configuration performed on such loggers usually
+ * affects all applications in the same Java Runtime.
+ *
The default LoggerFinder using {@code java.util.logging} as the backend
+ * maps {@code System.Logger} levels to
+ * {@linkplain java.util.logging.Level java.util.logging} levels
+ * of corresponding severity - as described in {@link Logger.Level
+ * Logger.Level}.
+ *
+ * @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.
+ */
+ static final RuntimePermission LOGGERFINDER_PERMISSION =
+ new RuntimePermission("loggerFinder");
+
+ /**
+ * Creates a new instance of {@code LoggerFinder}.
+ *
+ * @implNote It is recommended that a {@code LoggerFinder} service
+ * implementation does not perform any heavy initialization in its
+ * constructor, in order to avoid possible risks of deadlock or class
+ * loading cycles during the instantiation of the service provider.
+ *
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow 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}
+ * for the given {@code caller}.
+ *
+ * @param name the name of the logger.
+ * @param caller the class for which the logger is being requested;
+ * can be {@code null}.
+ *
+ * @return a {@link Logger logger} suitable for the given caller's
+ * use.
+ * @throws NullPointerException if {@code name} is {@code null} or
+ * {@code caller} is {@code null}.
+ * @throws SecurityException if a security manager is present and its
+ * {@code checkPermission} method doesn't allow the
+ * {@code RuntimePermission("loggerFinder")}.
+ */
+ public abstract Logger getLogger(String name, /* Module */ Class> caller);
+
+ /**
+ * Returns a localizable instance of {@link Logger Logger}
+ * for the given {@code 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 instance.
+ * 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.
+ *