/*
 * Copyright (c) 2015, 2016, 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 jdk.internal.logger;

import jdk.internal.misc.VM;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.Objects;
import java.lang.System.LoggerFinder;
import java.lang.System.Logger;
import java.lang.ref.ReferenceQueue;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.ResourceBundle;

Internal Service Provider Interface (SPI) that makes it possible to use java.util.logging as backend when the sun.util.logging.internal.LoggingProviderImpl is present.

The JDK default implementation of the LoggerFinder will attempt to locate and load an installed implementation of the DefaultLoggerFinder. If java.util.logging is present, this will usually resolve to an instance of sun.util.logging.internal.LoggingProviderImpl. Otherwise, if no concrete service provider is declared for DefaultLoggerFinder, the default implementation provided by this class will be used.

When the sun.util.logging.internal.LoggingProviderImpl is not present then the default implementation provided by this class is to use a simple logger that will log messages whose level is INFO and above to the console. These simple loggers are not configurable.

When configuration is needed, an application should either link with java.util.logging - and use the java.util.logging for configuration, or link with another implementation of the LoggerFinder that provides the necessary configuration.

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 or sun.util.logging.PlatformLogger.
/** * Internal Service Provider Interface (SPI) that makes it possible to use * {@code java.util.logging} as backend when the {@link * sun.util.logging.internal.LoggingProviderImpl * sun.util.logging.internal.LoggingProviderImpl} is present. * <p> * The JDK default implementation of the {@link LoggerFinder} will * attempt to locate and load an {@linkplain * java.util.ServiceLoader#loadInstalled(java.lang.Class) installed} * implementation of the {@code DefaultLoggerFinder}. If {@code java.util.logging} * is present, this will usually resolve to an instance of {@link * sun.util.logging.internal.LoggingProviderImpl sun.util.logging.internal.LoggingProviderImpl}. * Otherwise, if no concrete service provider is declared for * {@code DefaultLoggerFinder}, the default implementation provided by this class * will be used. * <p> * When the {@link sun.util.logging.internal.LoggingProviderImpl * sun.util.logging.internal.LoggingProviderImpl} is not present then the * default implementation provided by this class is to use a simple logger * that will log messages whose level is INFO and above to the console. * These simple loggers are not configurable. * <p> * When configuration is needed, an application should either link with * {@code java.util.logging} - and use the {@code java.util.logging} for * configuration, or link with {@link LoggerFinder another implementation} * of the {@link LoggerFinder} * that provides the necessary configuration. * * @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} or {@link sun.util.logging.PlatformLogger * sun.util.logging.PlatformLogger}. * * @see java.lang.System.LoggerFinder * @see jdk.internal.logger * @see sun.util.logging.internal * */
public class DefaultLoggerFinder extends LoggerFinder { static final RuntimePermission LOGGERFINDER_PERMISSION = new RuntimePermission("loggerFinder");
Creates a new instance of DefaultLoggerFinder.
Throws:
  • SecurityException – if the calling code does not have the RuntimePermission("loggerFinder")
/** * Creates a new instance of DefaultLoggerFinder. * @throws SecurityException if the calling code does not have the * {@code RuntimePermission("loggerFinder")} */
protected DefaultLoggerFinder() { this(checkPermission()); } private DefaultLoggerFinder(Void unused) { // nothing to do. } private static Void checkPermission() { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(LOGGERFINDER_PERMISSION); } return null; } // SharedLoggers is a default cache of loggers used when JUL is not // present - in that case we use instances of SimpleConsoleLogger which // cannot be directly configure through public APIs. // // We can therefore afford to simply maintain two domains - one for the // system, and one for the application. // static final class SharedLoggers { private final Map<String, Reference<Logger>> loggers = new HashMap<>(); private final ReferenceQueue<Logger> queue = new ReferenceQueue<>(); synchronized Logger get(Function<String, Logger> loggerSupplier, final String name) { Reference<? extends Logger> ref = loggers.get(name); Logger w = ref == null ? null : ref.get(); if (w == null) { w = loggerSupplier.apply(name); loggers.put(name, new WeakReference<>(w, queue)); } // Remove stale mapping... Collection<Reference<Logger>> values = null; while ((ref = queue.poll()) != null) { if (values == null) values = loggers.values(); values.remove(ref); } return w; } final static SharedLoggers system = new SharedLoggers(); final static SharedLoggers application = new SharedLoggers(); } public static boolean isSystem(Module m) { return AccessController.doPrivileged(new PrivilegedAction<>() { @Override public Boolean run() { // returns true if moduleCL is the platform class loader // or one of its ancestors. return VM.isSystemDomainLoader(m.getClassLoader()); } }); } @Override public final Logger getLogger(String name, Module module) { Objects.requireNonNull(name, "name"); Objects.requireNonNull(module, "module"); checkPermission(); return demandLoggerFor(name, module); } @Override public final Logger getLocalizedLogger(String name, ResourceBundle bundle, Module module) { return super.getLocalizedLogger(name, bundle, module); }
Returns a logger suitable for use within the given module.
Params:
  • name – The name of the logger.
  • module – The module on behalf of which the logger is created.
Throws:
  • SecurityException – if the calling code does not have the RuntimePermission("loggerFinder").
Implementation Requirements:The default implementation for this method is to return a simple logger that will print all messages of INFO level and above to the console. That simple logger is not configurable.
Returns:A logger suitable for the application usage.
/** * Returns a {@link Logger logger} suitable for use within the * given {@code module}. * * @implSpec The default implementation for this method is to return a * simple logger that will print all messages of INFO level and above * to the console. That simple logger is not configurable. * * @param name The name of the logger. * @param module The module on behalf of which the logger is created. * @return A {@link Logger logger} suitable for the application usage. * @throws SecurityException if the calling code does not have the * {@code RuntimePermission("loggerFinder")}. */
protected Logger demandLoggerFor(String name, Module module) { checkPermission(); if (isSystem(module)) { return SharedLoggers.system.get(SimpleConsoleLogger::makeSimpleLogger, name); } else { return SharedLoggers.application.get(SimpleConsoleLogger::makeSimpleLogger, name); } } }