Path: blob/master/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.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*/24package jdk.internal.logger;2526import java.io.FilePermission;27import java.security.AccessController;28import java.security.Permission;29import java.security.PrivilegedAction;30import java.util.Iterator;31import java.util.Locale;32import java.util.ServiceConfigurationError;33import java.util.ServiceLoader;34import sun.security.util.SecurityConstants;35import sun.security.action.GetPropertyAction;3637/**38* Helper class used to load the {@link java.lang.System.LoggerFinder}.39*/40public final class LoggerFinderLoader {41private static volatile System.LoggerFinder service;42private static final Object lock = new int[0];43static final Permission CLASSLOADER_PERMISSION =44SecurityConstants.GET_CLASSLOADER_PERMISSION;45static final Permission READ_PERMISSION =46new FilePermission("<<ALL FILES>>",47SecurityConstants.FILE_READ_ACTION);48public static final RuntimePermission LOGGERFINDER_PERMISSION =49new RuntimePermission("loggerFinder");5051// This is used to control how the LoggerFinderLoader handles52// errors when instantiating the LoggerFinder provider.53// ERROR => throws ServiceConfigurationError54// WARNING => Do not fail, use plain default (simple logger) implementation,55// prints warning on console. (this is the default)56// DEBUG => Do not fail, use plain default (simple logger) implementation,57// prints warning and exception stack trace on console.58// QUIET => Do not fail and stay silent.59private static enum ErrorPolicy { ERROR, WARNING, DEBUG, QUIET };6061// This class is static and cannot be instantiated.62private LoggerFinderLoader() {63throw new InternalError("LoggerFinderLoader cannot be instantiated");64}656667// Return the loaded LoggerFinder, or load it if not already loaded.68private static System.LoggerFinder service() {69if (service != null) return service;70synchronized(lock) {71if (service != null) return service;72service = loadLoggerFinder();73}74// Since the LoggerFinder is already loaded - we can stop using75// temporary loggers.76BootstrapLogger.redirectTemporaryLoggers();77return service;78}7980// Get configuration error policy81private static ErrorPolicy configurationErrorPolicy() {82String errorPolicy =83GetPropertyAction.privilegedGetProperty("jdk.logger.finder.error");84if (errorPolicy == null || errorPolicy.isEmpty()) {85return ErrorPolicy.WARNING;86}87try {88return ErrorPolicy.valueOf(errorPolicy.toUpperCase(Locale.ROOT));89} catch (IllegalArgumentException x) {90return ErrorPolicy.WARNING;91}92}9394// Whether multiple provider should be considered as an error.95// This is further submitted to the configuration error policy.96private static boolean ensureSingletonProvider() {97return Boolean.parseBoolean(98GetPropertyAction.privilegedGetProperty("jdk.logger.finder.singleton"));99}100101@SuppressWarnings("removal")102private static Iterator<System.LoggerFinder> findLoggerFinderProviders() {103final Iterator<System.LoggerFinder> iterator;104if (System.getSecurityManager() == null) {105iterator = ServiceLoader.load(System.LoggerFinder.class,106ClassLoader.getSystemClassLoader()).iterator();107} else {108final PrivilegedAction<Iterator<System.LoggerFinder>> pa =109() -> ServiceLoader.load(System.LoggerFinder.class,110ClassLoader.getSystemClassLoader()).iterator();111iterator = AccessController.doPrivileged(pa, null,112LOGGERFINDER_PERMISSION, CLASSLOADER_PERMISSION,113READ_PERMISSION);114}115return iterator;116}117118// Loads the LoggerFinder using ServiceLoader. If no LoggerFinder119// is found returns the default (possibly JUL based) implementation120private static System.LoggerFinder loadLoggerFinder() {121System.LoggerFinder result;122try {123// Iterator iterates with the access control context stored124// at ServiceLoader creation time.125final Iterator<System.LoggerFinder> iterator =126findLoggerFinderProviders();127if (iterator.hasNext()) {128result = iterator.next();129if (iterator.hasNext() && ensureSingletonProvider()) {130throw new ServiceConfigurationError(131"More than on LoggerFinder implementation");132}133} else {134result = loadDefaultImplementation();135}136} catch (Error | RuntimeException x) {137// next caller will get the plain default impl (not linked138// to java.util.logging)139service = result = new DefaultLoggerFinder();140ErrorPolicy errorPolicy = configurationErrorPolicy();141if (errorPolicy == ErrorPolicy.ERROR) {142// rethrow any exception as a ServiceConfigurationError.143if (x instanceof Error) {144throw x;145} else {146throw new ServiceConfigurationError(147"Failed to instantiate LoggerFinder provider; Using default.", x);148}149} else if (errorPolicy != ErrorPolicy.QUIET) {150// if QUIET just silently use the plain default impl151// otherwise, log a warning, possibly adding the exception152// stack trace (if DEBUG is specified).153SimpleConsoleLogger logger =154new SimpleConsoleLogger("jdk.internal.logger", false);155logger.log(System.Logger.Level.WARNING,156"Failed to instantiate LoggerFinder provider; Using default.");157if (errorPolicy == ErrorPolicy.DEBUG) {158logger.log(System.Logger.Level.WARNING,159"Exception raised trying to instantiate LoggerFinder", x);160}161}162}163return result;164}165166@SuppressWarnings("removal")167private static System.LoggerFinder loadDefaultImplementation() {168final SecurityManager sm = System.getSecurityManager();169final Iterator<DefaultLoggerFinder> iterator;170if (sm == null) {171iterator = ServiceLoader.loadInstalled(DefaultLoggerFinder.class).iterator();172} else {173// We use limited do privileged here - the minimum set of174// permissions required to 'see' the META-INF/services resources175// seems to be CLASSLOADER_PERMISSION and READ_PERMISSION.176// Note that do privileged is required because177// otherwise the SecurityManager will prevent the ServiceLoader178// from seeing the installed provider.179PrivilegedAction<Iterator<DefaultLoggerFinder>> pa = () ->180ServiceLoader.loadInstalled(DefaultLoggerFinder.class).iterator();181iterator = AccessController.doPrivileged(pa, null,182LOGGERFINDER_PERMISSION, CLASSLOADER_PERMISSION,183READ_PERMISSION);184}185DefaultLoggerFinder result = null;186try {187// Iterator iterates with the access control context stored188// at ServiceLoader creation time.189if (iterator.hasNext()) {190result = iterator.next();191}192} catch (RuntimeException x) {193throw new ServiceConfigurationError(194"Failed to instantiate default LoggerFinder", x);195}196if (result == null) {197result = new DefaultLoggerFinder();198}199return result;200}201202public static System.LoggerFinder getLoggerFinder() {203@SuppressWarnings("removal")204final SecurityManager sm = System.getSecurityManager();205if (sm != null) {206sm.checkPermission(LOGGERFINDER_PERMISSION);207}208return service();209}210211}212213214