Path: blob/master/src/java.logging/share/classes/sun/util/logging/internal/LoggingProviderImpl.java
41161 views
/*1* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/242526package sun.util.logging.internal;2728import java.security.AccessController;29import java.security.PrivilegedAction;30import java.util.ResourceBundle;31import java.util.function.Supplier;32import java.lang.System.LoggerFinder;33import java.lang.System.Logger;34import java.util.Objects;35import java.util.logging.LogManager;36import jdk.internal.logger.DefaultLoggerFinder;37import java.util.logging.LoggingPermission;38import sun.util.logging.PlatformLogger;39import sun.util.logging.PlatformLogger.ConfigurableBridge.LoggerConfiguration;4041/**42* This {@code LoggingProviderImpl} is the JDK internal implementation of the43* {@link jdk.internal.logger.DefaultLoggerFinder} which is used by44* the default implementation of the {@link Logger}45* when no {@link LoggerFinder} is found46* and {@code java.util.logging} is present.47* When {@code java.util.logging} is present, the {@code LoggingProviderImpl}48* is {@linkplain java.util.ServiceLoader#loadInstalled(Class) installed} as49* an internal service provider, making it possible to use {@code java.util.logging}50* as the backend for loggers returned by the default LoggerFinder implementation.51* <p>52* This implementation of {@link DefaultLoggerFinder} returns instances of53* {@link java.lang.System.Logger} which54* delegate to a wrapped instance of {@link java.util.logging.Logger55* java.util.logging.Logger}.56* <br>57* Loggers returned by this class can therefore be configured by accessing58* their wrapped implementation through the regular {@code java.util.logging}59* APIs - such as {@link java.util.logging.LogManager java.util.logging.LogManager}60* and {@link java.util.logging.Logger java.util.logging.Logger}.61*62* @apiNote Programmers are not expected to call this class directly.63* Instead they should rely on the static methods defined by64* {@link java.lang.System java.lang.System}.65* <p>66* To replace this default67* {@code java.util.logging} backend, an application is expected to install68* its own {@link java.lang.System.LoggerFinder}.69*70* @see java.lang.System.Logger71* @see java.lang.System.LoggerFinder72* @see sun.util.logging.PlatformLogger.Bridge73* @see java.lang.System74* @see jdk.internal.logger75* @see jdk.internal.logger76*77*/78public final class LoggingProviderImpl extends DefaultLoggerFinder {79static final RuntimePermission LOGGERFINDER_PERMISSION =80new RuntimePermission("loggerFinder");81private static final LoggingPermission LOGGING_CONTROL_PERMISSION =82new LoggingPermission("control", null);8384/**85* Creates a new instance of LoggingProviderImpl.86* @throws SecurityException if the calling code does not have the87* {@code RuntimePermission("loggerFinder")}.88*/89public LoggingProviderImpl() {90}9192/**93* A logger that delegates to a java.util.logging.Logger delegate.94*/95static final class JULWrapper extends LoggerConfiguration96implements System.Logger, PlatformLogger.Bridge,97PlatformLogger.ConfigurableBridge {9899100private static final java.util.logging.Level[] spi2JulLevelMapping = {101java.util.logging.Level.ALL, // mapped from ALL102java.util.logging.Level.FINER, // mapped from TRACE103java.util.logging.Level.FINE, // mapped from DEBUG104java.util.logging.Level.INFO, // mapped from INFO105java.util.logging.Level.WARNING, // mapped from WARNING106java.util.logging.Level.SEVERE, // mapped from ERROR107java.util.logging.Level.OFF // mapped from OFF108};109110private static final java.util.logging.Level[] platform2JulLevelMapping = {111java.util.logging.Level.ALL, // mapped from ALL112java.util.logging.Level.FINEST, // mapped from FINEST113java.util.logging.Level.FINER, // mapped from FINER114java.util.logging.Level.FINE, // mapped from FINE115java.util.logging.Level.CONFIG, // mapped from CONFIG116java.util.logging.Level.INFO, // mapped from INFO117java.util.logging.Level.WARNING, // mapped from WARNING118java.util.logging.Level.SEVERE, // mapped from SEVERE119java.util.logging.Level.OFF // mapped from OFF120};121122private final java.util.logging.Logger julLogger;123124125private JULWrapper(java.util.logging.Logger logger) {126this.julLogger = logger;127}128129@Override130public String getName() {131return julLogger.getName();132}133@Override134public void log(sun.util.logging.PlatformLogger.Level level, String msg, Throwable throwable) {135julLogger.log(toJUL(level), msg, throwable);136}137138@Override139public void log(sun.util.logging.PlatformLogger.Level level, String format, Object... params) {140julLogger.log(toJUL(level), format, params);141}142143@Override144public void log(sun.util.logging.PlatformLogger.Level level, String msg) {145julLogger.log(toJUL(level), msg);146}147148@Override149public void log(sun.util.logging.PlatformLogger.Level level, Supplier<String> msgSuppier) {150julLogger.log(toJUL(level), msgSuppier);151}152153@Override154public void log(sun.util.logging.PlatformLogger.Level level, Throwable thrown, Supplier<String> msgSuppier) {155julLogger.log(toJUL(level), thrown, msgSuppier);156}157158@Override159public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Throwable throwable) {160julLogger.logrb(toJUL(level), bundle, key, throwable);161}162163@Override164public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Object... params) {165julLogger.logrb(toJUL(level), bundle, key, params);166}167168@Override169public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, String msg) {170julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg);171}172173@Override174public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,175Supplier<String> msgSupplier) {176julLogger.logp(toJUL(level), sourceClass, sourceMethod, msgSupplier);177}178179@Override180public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,181String msg, Object... params) {182julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, params);183}184185@Override186public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,187String msg, Throwable thrown) {188julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, thrown);189}190191@Override192public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,193Throwable thrown, Supplier<String> msgSupplier) {194julLogger.logp(toJUL(level), sourceClass, sourceMethod,195thrown, msgSupplier);196}197198@Override199public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,200ResourceBundle bundle, String key, Object... params) {201julLogger.logrb(toJUL(level), sourceClass, sourceMethod,202bundle, key, params);203}204205@Override206public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,207ResourceBundle bundle, String key, Throwable thrown) {208julLogger.logrb(toJUL(level), sourceClass, sourceMethod,209bundle, key, thrown);210}211212@Override213public boolean isLoggable(sun.util.logging.PlatformLogger.Level level) {214return julLogger.isLoggable(toJUL(level));215}216217// -----------------------------------------------------------------218// Generic methods taking a Level as parameter219// -----------------------------------------------------------------220221222@Override223public boolean isLoggable(Level level) {224return julLogger.isLoggable(toJUL(level));225}226227@Override228public void log(Level level, String msg) {229julLogger.log(toJUL(level), msg);230}231232@Override233public void log(Level level,234Supplier<String> msgSupplier) {235// We need to check for null here to satisfy the contract236// of System.Logger - because the underlying implementation237// of julLogger will check for it only if the level is238// loggable239Objects.requireNonNull(msgSupplier);240julLogger.log(toJUL(level), msgSupplier);241}242243@Override244public void log(Level level, Object obj) {245// We need to check for null here to satisfy the contract246// of System.Logger - because the underlying implementation247// of julLogger will check for it only if the level is248// loggable249Objects.requireNonNull(obj);250julLogger.log(toJUL(level), () -> obj.toString());251}252253@Override254public void log(Level level,255String msg, Throwable thrown) {256julLogger.log(toJUL(level), msg, thrown);257}258259@Override260public void log(Level level, Supplier<String> msgSupplier,261Throwable thrown) {262// We need to check for null here to satisfy the contract263// of System.Logger - because the underlying implementation264// of julLogger will check for it only if the level is265// loggable266Objects.requireNonNull(msgSupplier);267julLogger.log(toJUL(level), thrown, msgSupplier);268}269270@Override271public void log(Level level,272String format, Object... params) {273julLogger.log(toJUL(level), format, params);274}275276@Override277public void log(Level level, ResourceBundle bundle,278String key, Throwable thrown) {279julLogger.logrb(toJUL(level), bundle, key, thrown);280}281282@Override283public void log(Level level, ResourceBundle bundle,284String format, Object... params) {285julLogger.logrb(toJUL(level), bundle, format, params);286}287288static java.util.logging.Level toJUL(Level level) {289if (level == null) return null;290assert level.ordinal() < spi2JulLevelMapping.length;291return spi2JulLevelMapping[level.ordinal()];292}293294// ---------------------------------------------------------295// Methods from PlatformLogger.Bridge296// ---------------------------------------------------------297298@Override299public boolean isEnabled() {300return julLogger.getLevel() != java.util.logging.Level.OFF;301}302303@Override304public PlatformLogger.Level getPlatformLevel() {305final java.util.logging.Level javaLevel = julLogger.getLevel();306if (javaLevel == null) return null;307try {308return PlatformLogger.Level.valueOf(javaLevel.getName());309} catch (IllegalArgumentException e) {310return PlatformLogger.Level.valueOf(javaLevel.intValue());311}312}313314@Override315public void setPlatformLevel(PlatformLogger.Level level) {316// null is allowed here317julLogger.setLevel(toJUL(level));318}319320@Override321public LoggerConfiguration getLoggerConfiguration() {322return this;323}324325static java.util.logging.Level toJUL(PlatformLogger.Level level) {326// The caller will throw if null is invalid in its context.327// There's at least one case where a null level is valid.328if (level == null) return null;329assert level.ordinal() < platform2JulLevelMapping.length;330return platform2JulLevelMapping[level.ordinal()];331}332333@Override334public boolean equals(Object obj) {335return (obj instanceof JULWrapper)336&& obj.getClass() == this.getClass()337&& ((JULWrapper)obj).julLogger == this.julLogger;338}339340@Override341public int hashCode() {342return julLogger.hashCode();343}344345// A JULWrapper is just a stateless thin shell over a JUL logger - so346// for a given JUL logger, we could always return the same wrapper.347//348// This is an optimization which may - or may not - be worth the349// trouble: if many classes use the same logger, and if each class350// keeps a reference to that logger, then caching the wrapper will351// be worthwhile. Otherwise, if each logger is only referred once,352// then the cache will eat up more memory than would be necessary...353//354// Here is an example of how we could implement JULWrapper.of(...)355// if we wanted to create at most one wrapper instance for each logger356// instance:357//358// static final WeakHashMap<JULWrapper, WeakReference<JULWrapper>>359// wrappers = new WeakHashMap<>();360//361// static JULWrapper of(java.util.logging.Logger logger) {362//363// // First access without synchronizing364// final JULWrapper candidate = new JULWrapper(logger);365// WeakReference<JULWrapper> ref = wrappers.get(candidate);366// JULWrapper found = ref.get();367//368// // OK - we found it - lets return it.369// if (found != null) return found;370//371// // Not found. Need to synchronize.372// synchronized (wrappers) {373// ref = wrappers.get(candidate);374// found = ref.get();375// if (found == null) {376// wrappers.put(candidate, new WeakReference<>(candidate));377// found = candidate;378// }379// }380// assert found != null;381// return found;382// }383//384// But given that it may end up eating more memory in the nominal case385// (where each class that does logging has its own logger with the386// class name as logger name and stashes that logger away in a static387// field, thus making the cache redundant - as only one wrapper will388// ever be created anyway) - then we will simply return a new wrapper389// for each invocation of JULWrapper.of(...) - which may390// still prove more efficient in terms of memory consumption...391//392static JULWrapper of(java.util.logging.Logger logger) {393return new JULWrapper(logger);394}395396397}398399/**400* Creates a java.util.logging.Logger for the given module.401* @param name the logger name.402* @param module the module for which the logger should be created.403* @return a Logger suitable for use in the given module.404*/405@SuppressWarnings("removal")406private static java.util.logging.Logger demandJULLoggerFor(final String name,407Module module) {408final LogManager manager = LogManager.getLogManager();409final SecurityManager sm = System.getSecurityManager();410if (sm == null) {411return logManagerAccess.demandLoggerFor(manager, name, module);412} else {413final PrivilegedAction<java.util.logging.Logger> pa =414() -> logManagerAccess.demandLoggerFor(manager, name, module);415return AccessController.doPrivileged(pa, null, LOGGING_CONTROL_PERMISSION);416}417}418419/**420* {@inheritDoc}421*422* @apiNote The logger returned by this method can be configured through423* its {@linkplain java.util.logging.LogManager#getLogger(String)424* corresponding java.util.logging.Logger backend}.425*426* @return {@inheritDoc}427* @throws SecurityException if the calling code doesn't have the428* {@code RuntimePermission("loggerFinder")}.429*/430@Override431protected Logger demandLoggerFor(String name, Module module) {432@SuppressWarnings("removal")433final SecurityManager sm = System.getSecurityManager();434if (sm != null) {435sm.checkPermission(LOGGERFINDER_PERMISSION);436}437return JULWrapper.of(demandJULLoggerFor(name,module));438}439440public static interface LogManagerAccess {441java.util.logging.Logger demandLoggerFor(LogManager manager,442String name, Module module);443}444445// Hook for tests446public static LogManagerAccess getLogManagerAccess() {447@SuppressWarnings("removal")448final SecurityManager sm = System.getSecurityManager();449if (sm != null) {450sm.checkPermission(LOGGING_CONTROL_PERMISSION);451}452// Triggers initialization of accessJulLogger if not set.453if (logManagerAccess == null) LogManager.getLogManager();454return logManagerAccess;455}456457458private static volatile LogManagerAccess logManagerAccess;459public static void setLogManagerAccess(LogManagerAccess accesLoggers) {460@SuppressWarnings("removal")461final SecurityManager sm = System.getSecurityManager();462if (sm != null) {463sm.checkPermission(LOGGING_CONTROL_PERMISSION);464}465logManagerAccess = accesLoggers;466}467468}469470471