Path: blob/master/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java
41159 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*/2425package jdk.internal.logger;2627import jdk.internal.misc.VM;2829import java.lang.ref.Reference;30import java.lang.ref.WeakReference;31import java.util.HashMap;32import java.util.Map;33import java.util.function.Function;34import java.util.Objects;35import java.lang.System.LoggerFinder;36import java.lang.System.Logger;37import java.lang.ref.ReferenceQueue;38import java.security.AccessController;39import java.security.PrivilegedAction;40import java.util.Collection;41import java.util.ResourceBundle;4243/**44* Internal Service Provider Interface (SPI) that makes it possible to use45* {@code java.util.logging} as backend when the {@link46* sun.util.logging.internal.LoggingProviderImpl47* sun.util.logging.internal.LoggingProviderImpl} is present.48* <p>49* The JDK default implementation of the {@link LoggerFinder} will50* attempt to locate and load an {@linkplain51* java.util.ServiceLoader#loadInstalled(java.lang.Class) installed}52* implementation of the {@code DefaultLoggerFinder}. If {@code java.util.logging}53* is present, this will usually resolve to an instance of {@link54* sun.util.logging.internal.LoggingProviderImpl sun.util.logging.internal.LoggingProviderImpl}.55* Otherwise, if no concrete service provider is declared for56* {@code DefaultLoggerFinder}, the default implementation provided by this class57* will be used.58* <p>59* When the {@link sun.util.logging.internal.LoggingProviderImpl60* sun.util.logging.internal.LoggingProviderImpl} is not present then the61* default implementation provided by this class is to use a simple logger62* that will log messages whose level is INFO and above to the console.63* These simple loggers are not configurable.64* <p>65* When configuration is needed, an application should either link with66* {@code java.util.logging} - and use the {@code java.util.logging} for67* configuration, or link with {@link LoggerFinder another implementation}68* of the {@link LoggerFinder}69* that provides the necessary configuration.70*71* @apiNote Programmers are not expected to call this class directly.72* Instead they should rely on the static methods defined by {@link73* java.lang.System java.lang.System} or {@link sun.util.logging.PlatformLogger74* sun.util.logging.PlatformLogger}.75*76* @see java.lang.System.LoggerFinder77* @see jdk.internal.logger78* @see sun.util.logging.internal79*80*/81public class DefaultLoggerFinder extends LoggerFinder {8283static final RuntimePermission LOGGERFINDER_PERMISSION =84new RuntimePermission("loggerFinder");8586/**87* Creates a new instance of DefaultLoggerFinder.88* @throws SecurityException if the calling code does not have the89* {@code RuntimePermission("loggerFinder")}90*/91protected DefaultLoggerFinder() {92this(checkPermission());93}9495private DefaultLoggerFinder(Void unused) {96// nothing to do.97}9899private static Void checkPermission() {100@SuppressWarnings("removal")101final SecurityManager sm = System.getSecurityManager();102if (sm != null) {103sm.checkPermission(LOGGERFINDER_PERMISSION);104}105return null;106}107108// SharedLoggers is a default cache of loggers used when JUL is not109// present - in that case we use instances of SimpleConsoleLogger which110// cannot be directly configure through public APIs.111//112// We can therefore afford to simply maintain two domains - one for the113// system, and one for the application.114//115static final class SharedLoggers {116private final Map<String, Reference<Logger>> loggers =117new HashMap<>();118private final ReferenceQueue<Logger> queue = new ReferenceQueue<>();119120synchronized Logger get(Function<String, Logger> loggerSupplier, final String name) {121Reference<? extends Logger> ref = loggers.get(name);122Logger w = ref == null ? null : ref.get();123if (w == null) {124w = loggerSupplier.apply(name);125loggers.put(name, new WeakReference<>(w, queue));126}127128// Remove stale mapping...129Collection<Reference<Logger>> values = null;130while ((ref = queue.poll()) != null) {131if (values == null) values = loggers.values();132values.remove(ref);133}134return w;135}136137static final SharedLoggers system = new SharedLoggers();138static final SharedLoggers application = new SharedLoggers();139}140141@SuppressWarnings("removal")142public static boolean isSystem(Module m) {143return AccessController.doPrivileged(new PrivilegedAction<>() {144@Override145public Boolean run() {146// returns true if moduleCL is the platform class loader147// or one of its ancestors.148return VM.isSystemDomainLoader(m.getClassLoader());149}150});151}152153@Override154public final Logger getLogger(String name, Module module) {155Objects.requireNonNull(name, "name");156Objects.requireNonNull(module, "module");157checkPermission();158return demandLoggerFor(name, module);159}160161@Override162public final Logger getLocalizedLogger(String name, ResourceBundle bundle,163Module module) {164return super.getLocalizedLogger(name, bundle, module);165}166167/**168* Returns a {@link Logger logger} suitable for use within the169* given {@code module}.170*171* @implSpec The default implementation for this method is to return a172* simple logger that will print all messages of INFO level and above173* to the console. That simple logger is not configurable.174*175* @param name The name of the logger.176* @param module The module on behalf of which the logger is created.177* @return A {@link Logger logger} suitable for the application usage.178* @throws SecurityException if the calling code does not have the179* {@code RuntimePermission("loggerFinder")}.180*/181protected Logger demandLoggerFor(String name, Module module) {182checkPermission();183if (isSystem(module)) {184return SharedLoggers.system.get(SimpleConsoleLogger::makeSimpleLogger, name);185} else {186return SharedLoggers.application.get(SimpleConsoleLogger::makeSimpleLogger, name);187}188}189190}191192193