/*
 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


package sun.util.logging.internal;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ResourceBundle;
import java.util.function.Supplier;
import java.lang.System.LoggerFinder;
import java.lang.System.Logger;
import java.util.Objects;
import java.util.logging.LogManager;
import jdk.internal.logger.DefaultLoggerFinder;
import java.util.logging.LoggingPermission;
import sun.util.logging.PlatformLogger;
import sun.util.logging.PlatformLogger.ConfigurableBridge.LoggerConfiguration;

This LoggingProviderImpl is the JDK internal implementation of the DefaultLoggerFinder which is used by the default implementation of the Logger when no LoggerFinder is found and java.util.logging is present. When java.util.logging is present, the LoggingProviderImpl is installed as an internal service provider, making it possible to use java.util.logging as the backend for loggers returned by the default LoggerFinder implementation.

This implementation of DefaultLoggerFinder returns instances of Logger which delegate to a wrapped instance of java.util.logging.Logger.
Loggers returned by this class can therefore be configured by accessing their wrapped implementation through the regular java.util.logging APIs - such as java.util.logging.LogManager and java.util.logging.Logger.

See Also:
API Note:Programmers are not expected to call this class directly. Instead they should rely on the static methods defined by java.lang.System.

To replace this default java.util.logging backend, an application is expected to install its own LoggerFinder.

/** * This {@code LoggingProviderImpl} is the JDK internal implementation of the * {@link jdk.internal.logger.DefaultLoggerFinder} which is used by * the default implementation of the {@link Logger} * when no {@link LoggerFinder} is found * and {@code java.util.logging} is present. * When {@code java.util.logging} is present, the {@code LoggingProviderImpl} * is {@linkplain java.util.ServiceLoader#loadInstalled(Class) installed} as * an internal service provider, making it possible to use {@code java.util.logging} * as the backend for loggers returned by the default LoggerFinder implementation. * <p> * This implementation of {@link DefaultLoggerFinder} returns instances of * {@link java.lang.System.Logger} which * delegate to a wrapped instance of {@link java.util.logging.Logger * java.util.logging.Logger}. * <br> * Loggers returned by this class can therefore be configured by accessing * their wrapped implementation through the regular {@code java.util.logging} * APIs - such as {@link java.util.logging.LogManager java.util.logging.LogManager} * and {@link java.util.logging.Logger java.util.logging.Logger}. * * @apiNote Programmers are not expected to call this class directly. * Instead they should rely on the static methods defined by * {@link java.lang.System java.lang.System}. * <p> * To replace this default * {@code java.util.logging} backend, an application is expected to install * its own {@link java.lang.System.LoggerFinder}. * * @see java.lang.System.Logger * @see java.lang.System.LoggerFinder * @see sun.util.logging.PlatformLogger.Bridge * @see java.lang.System * @see jdk.internal.logger * @see jdk.internal.logger * */
public final class LoggingProviderImpl extends DefaultLoggerFinder { static final RuntimePermission LOGGERFINDER_PERMISSION = new RuntimePermission("loggerFinder"); private static final LoggingPermission LOGGING_CONTROL_PERMISSION = new LoggingPermission("control", null);
Creates a new instance of LoggingProviderImpl.
Throws:
  • SecurityException – if the calling code does not have the RuntimePermission("loggerFinder").
/** * Creates a new instance of LoggingProviderImpl. * @throws SecurityException if the calling code does not have the * {@code RuntimePermission("loggerFinder")}. */
public LoggingProviderImpl() { }
A logger that delegates to a java.util.logging.Logger delegate.
/** * A logger that delegates to a java.util.logging.Logger delegate. */
static final class JULWrapper extends LoggerConfiguration implements System.Logger, PlatformLogger.Bridge, PlatformLogger.ConfigurableBridge { private static final java.util.logging.Level[] spi2JulLevelMapping = { java.util.logging.Level.ALL, // mapped from ALL java.util.logging.Level.FINER, // mapped from TRACE java.util.logging.Level.FINE, // mapped from DEBUG java.util.logging.Level.INFO, // mapped from INFO java.util.logging.Level.WARNING, // mapped from WARNING java.util.logging.Level.SEVERE, // mapped from ERROR java.util.logging.Level.OFF // mapped from OFF }; private static final java.util.logging.Level[] platform2JulLevelMapping = { java.util.logging.Level.ALL, // mapped from ALL java.util.logging.Level.FINEST, // mapped from FINEST java.util.logging.Level.FINER, // mapped from FINER java.util.logging.Level.FINE, // mapped from FINE java.util.logging.Level.CONFIG, // mapped from CONFIG java.util.logging.Level.INFO, // mapped from INFO java.util.logging.Level.WARNING, // mapped from WARNING java.util.logging.Level.SEVERE, // mapped from SEVERE java.util.logging.Level.OFF // mapped from OFF }; private final java.util.logging.Logger julLogger; private JULWrapper(java.util.logging.Logger logger) { this.julLogger = logger; } @Override public String getName() { return julLogger.getName(); } @Override public void log(sun.util.logging.PlatformLogger.Level level, String msg, Throwable throwable) { julLogger.log(toJUL(level), msg, throwable); } @Override public void log(sun.util.logging.PlatformLogger.Level level, String format, Object... params) { julLogger.log(toJUL(level), format, params); } @Override public void log(sun.util.logging.PlatformLogger.Level level, String msg) { julLogger.log(toJUL(level), msg); } @Override public void log(sun.util.logging.PlatformLogger.Level level, Supplier<String> msgSuppier) { julLogger.log(toJUL(level), msgSuppier); } @Override public void log(sun.util.logging.PlatformLogger.Level level, Throwable thrown, Supplier<String> msgSuppier) { julLogger.log(toJUL(level), thrown, msgSuppier); } @Override public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Throwable throwable) { julLogger.logrb(toJUL(level), bundle, key, throwable); } @Override public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Object... params) { julLogger.logrb(toJUL(level), bundle, key, params); } @Override public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, String msg) { julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg); } @Override public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, Supplier<String> msgSupplier) { julLogger.logp(toJUL(level), sourceClass, sourceMethod, msgSupplier); } @Override public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, String msg, Object... params) { julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, params); } @Override public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, String msg, Throwable thrown) { julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, thrown); } @Override public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, Throwable thrown, Supplier<String> msgSupplier) { julLogger.logp(toJUL(level), sourceClass, sourceMethod, thrown, msgSupplier); } @Override public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, ResourceBundle bundle, String key, Object... params) { julLogger.logrb(toJUL(level), sourceClass, sourceMethod, bundle, key, params); } @Override public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, ResourceBundle bundle, String key, Throwable thrown) { julLogger.logrb(toJUL(level), sourceClass, sourceMethod, bundle, key, thrown); } @Override public boolean isLoggable(sun.util.logging.PlatformLogger.Level level) { return julLogger.isLoggable(toJUL(level)); } // ----------------------------------------------------------------- // Generic methods taking a Level as parameter // ----------------------------------------------------------------- @Override public boolean isLoggable(Level level) { return julLogger.isLoggable(toJUL(level)); } @Override public void log(Level level, String msg) { julLogger.log(toJUL(level), msg); } @Override public void log(Level level, Supplier<String> msgSupplier) { // We need to check for null here to satisfy the contract // of System.Logger - because the underlying implementation // of julLogger will check for it only if the level is // loggable Objects.requireNonNull(msgSupplier); julLogger.log(toJUL(level), msgSupplier); } @Override public void log(Level level, Object obj) { // We need to check for null here to satisfy the contract // of System.Logger - because the underlying implementation // of julLogger will check for it only if the level is // loggable Objects.requireNonNull(obj); julLogger.log(toJUL(level), () -> obj.toString()); } @Override public void log(Level level, String msg, Throwable thrown) { julLogger.log(toJUL(level), msg, thrown); } @Override public void log(Level level, Supplier<String> msgSupplier, Throwable thrown) { // We need to check for null here to satisfy the contract // of System.Logger - because the underlying implementation // of julLogger will check for it only if the level is // loggable Objects.requireNonNull(msgSupplier); julLogger.log(toJUL(level), thrown, msgSupplier); } @Override public void log(Level level, String format, Object... params) { julLogger.log(toJUL(level), format, params); } @Override public void log(Level level, ResourceBundle bundle, String key, Throwable thrown) { julLogger.logrb(toJUL(level), bundle, key, thrown); } @Override public void log(Level level, ResourceBundle bundle, String format, Object... params) { julLogger.logrb(toJUL(level), bundle, format, params); } static java.util.logging.Level toJUL(Level level) { if (level == null) return null; assert level.ordinal() < spi2JulLevelMapping.length; return spi2JulLevelMapping[level.ordinal()]; } // --------------------------------------------------------- // Methods from PlatformLogger.Bridge // --------------------------------------------------------- @Override public boolean isEnabled() { return julLogger.getLevel() != java.util.logging.Level.OFF; } @Override public PlatformLogger.Level getPlatformLevel() { final java.util.logging.Level javaLevel = julLogger.getLevel(); if (javaLevel == null) return null; try { return PlatformLogger.Level.valueOf(javaLevel.getName()); } catch (IllegalArgumentException e) { return PlatformLogger.Level.valueOf(javaLevel.intValue()); } } @Override public void setPlatformLevel(PlatformLogger.Level level) { // null is allowed here julLogger.setLevel(toJUL(level)); } @Override public LoggerConfiguration getLoggerConfiguration() { return this; } static java.util.logging.Level toJUL(PlatformLogger.Level level) { // The caller will throw if null is invalid in its context. // There's at least one case where a null level is valid. if (level == null) return null; assert level.ordinal() < platform2JulLevelMapping.length; return platform2JulLevelMapping[level.ordinal()]; } @Override public boolean equals(Object obj) { return (obj instanceof JULWrapper) && obj.getClass() == this.getClass() && ((JULWrapper)obj).julLogger == this.julLogger; } @Override public int hashCode() { return julLogger.hashCode(); } // A JULWrapper is just a stateless thin shell over a JUL logger - so // for a given JUL logger, we could always return the same wrapper. // // This is an optimization which may - or may not - be worth the // trouble: if many classes use the same logger, and if each class // keeps a reference to that logger, then caching the wrapper will // be worthwhile. Otherwise, if each logger is only referred once, // then the cache will eat up more memory than would be necessary... // // Here is an example of how we could implement JULWrapper.of(...) // if we wanted to create at most one wrapper instance for each logger // instance: // // static final WeakHashMap<JULWrapper, WeakReference<JULWrapper>> // wrappers = new WeakHashMap<>(); // // static JULWrapper of(java.util.logging.Logger logger) { // // // First access without synchronizing // final JULWrapper candidate = new JULWrapper(logger); // WeakReference<JULWrapper> ref = wrappers.get(candidate); // JULWrapper found = ref.get(); // // // OK - we found it - lets return it. // if (found != null) return found; // // // Not found. Need to synchronize. // synchronized (wrappers) { // ref = wrappers.get(candidate); // found = ref.get(); // if (found == null) { // wrappers.put(candidate, new WeakReference<>(candidate)); // found = candidate; // } // } // assert found != null; // return found; // } // // But given that it may end up eating more memory in the nominal case // (where each class that does logging has its own logger with the // class name as logger name and stashes that logger away in a static // field, thus making the cache redundant - as only one wrapper will // ever be created anyway) - then we will simply return a new wrapper // for each invocation of JULWrapper.of(...) - which may // still prove more efficient in terms of memory consumption... // static JULWrapper of(java.util.logging.Logger logger) { return new JULWrapper(logger); } }
Creates a java.util.logging.Logger for the given module.
Params:
  • name – the logger name.
  • module – the module for which the logger should be created.
Returns:a Logger suitable for use in the given module.
/** * Creates a java.util.logging.Logger for the given module. * @param name the logger name. * @param module the module for which the logger should be created. * @return a Logger suitable for use in the given module. */
private static java.util.logging.Logger demandJULLoggerFor(final String name, Module module) { final LogManager manager = LogManager.getLogManager(); final SecurityManager sm = System.getSecurityManager(); if (sm == null) { return logManagerAccess.demandLoggerFor(manager, name, module); } else { final PrivilegedAction<java.util.logging.Logger> pa = () -> logManagerAccess.demandLoggerFor(manager, name, module); return AccessController.doPrivileged(pa, null, LOGGING_CONTROL_PERMISSION); } }
{@inheritDoc}
Throws:
  • SecurityException – if the calling code doesn't have the RuntimePermission("loggerFinder").
API Note:The logger returned by this method can be configured through its corresponding java.util.logging.Logger backend.
Returns:{@inheritDoc}
/** * {@inheritDoc} * * @apiNote The logger returned by this method can be configured through * its {@linkplain java.util.logging.LogManager#getLogger(String) * corresponding java.util.logging.Logger backend}. * * @return {@inheritDoc} * @throws SecurityException if the calling code doesn't have the * {@code RuntimePermission("loggerFinder")}. */
@Override protected Logger demandLoggerFor(String name, Module module) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOGGERFINDER_PERMISSION); } return JULWrapper.of(demandJULLoggerFor(name,module)); } public static interface LogManagerAccess { java.util.logging.Logger demandLoggerFor(LogManager manager, String name, Module module); } // Hook for tests public static LogManagerAccess getLogManagerAccess() { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOGGING_CONTROL_PERMISSION); } // Triggers initialization of accessJulLogger if not set. if (logManagerAccess == null) LogManager.getLogManager(); return logManagerAccess; } private static volatile LogManagerAccess logManagerAccess; public static void setLogManagerAccess(LogManagerAccess accesLoggers) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOGGING_CONTROL_PERMISSION); } logManagerAccess = accesLoggers; } }