| /* |
| * 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 jdk.internal.logger; |
| |
| import java.io.FilePermission; |
| import java.security.AccessController; |
| import java.security.Permission; |
| import java.security.PrivilegedAction; |
| import java.util.Iterator; |
| import java.util.Locale; |
| import java.util.ServiceConfigurationError; |
| import java.util.ServiceLoader; |
| import sun.security.util.SecurityConstants; |
| import sun.security.action.GetPropertyAction; |
| |
| /** |
| * Helper class used to load the {@link java.lang.System.LoggerFinder}. |
| */ |
| public final class LoggerFinderLoader { |
| private static volatile System.LoggerFinder service; |
| private static final Object lock = new int[0]; |
| static final Permission CLASSLOADER_PERMISSION = |
| SecurityConstants.GET_CLASSLOADER_PERMISSION; |
| static final Permission READ_PERMISSION = |
| new FilePermission("<<ALL FILES>>", |
| SecurityConstants.FILE_READ_ACTION); |
| public static final RuntimePermission LOGGERFINDER_PERMISSION = |
| new RuntimePermission("loggerFinder"); |
| |
| // This is used to control how the LoggerFinderLoader handles |
| // errors when instantiating the LoggerFinder provider. |
| // ERROR => throws ServiceConfigurationError |
| // WARNING => Do not fail, use plain default (simple logger) implementation, |
| // prints warning on console. (this is the default) |
| // DEBUG => Do not fail, use plain default (simple logger) implementation, |
| // prints warning and exception stack trace on console. |
| // QUIET => Do not fail and stay silent. |
| private static enum ErrorPolicy { ERROR, WARNING, DEBUG, QUIET }; |
| |
| // This class is static and cannot be instantiated. |
| private LoggerFinderLoader() { |
| throw new InternalError("LoggerFinderLoader cannot be instantiated"); |
| } |
| |
| |
| // Return the loaded LoggerFinder, or load it if not already loaded. |
| private static System.LoggerFinder service() { |
| if (service != null) return service; |
| synchronized(lock) { |
| if (service != null) return service; |
| service = loadLoggerFinder(); |
| } |
| // Since the LoggerFinder is already loaded - we can stop using |
| // temporary loggers. |
| BootstrapLogger.redirectTemporaryLoggers(); |
| return service; |
| } |
| |
| // Get configuration error policy |
| private static ErrorPolicy configurationErrorPolicy() { |
| String errorPolicy = |
| GetPropertyAction.privilegedGetProperty("jdk.logger.finder.error"); |
| if (errorPolicy == null || errorPolicy.isEmpty()) { |
| return ErrorPolicy.WARNING; |
| } |
| try { |
| return ErrorPolicy.valueOf(errorPolicy.toUpperCase(Locale.ROOT)); |
| } catch (IllegalArgumentException x) { |
| return ErrorPolicy.WARNING; |
| } |
| } |
| |
| // Whether multiple provider should be considered as an error. |
| // This is further submitted to the configuration error policy. |
| private static boolean ensureSingletonProvider() { |
| return Boolean.parseBoolean( |
| GetPropertyAction.privilegedGetProperty("jdk.logger.finder.singleton")); |
| } |
| |
| private static Iterator<System.LoggerFinder> findLoggerFinderProviders() { |
| final Iterator<System.LoggerFinder> iterator; |
| if (System.getSecurityManager() == null) { |
| iterator = ServiceLoader.load(System.LoggerFinder.class, |
| ClassLoader.getSystemClassLoader()).iterator(); |
| } else { |
| final PrivilegedAction<Iterator<System.LoggerFinder>> pa = |
| () -> ServiceLoader.load(System.LoggerFinder.class, |
| ClassLoader.getSystemClassLoader()).iterator(); |
| iterator = AccessController.doPrivileged(pa, null, |
| LOGGERFINDER_PERMISSION, CLASSLOADER_PERMISSION, |
| READ_PERMISSION); |
| } |
| return iterator; |
| } |
| |
| // Loads the LoggerFinder using ServiceLoader. If no LoggerFinder |
| // is found returns the default (possibly JUL based) implementation |
| private static System.LoggerFinder loadLoggerFinder() { |
| System.LoggerFinder result; |
| try { |
| // Iterator iterates with the access control context stored |
| // at ServiceLoader creation time. |
| final Iterator<System.LoggerFinder> iterator = |
| findLoggerFinderProviders(); |
| if (iterator.hasNext()) { |
| result = iterator.next(); |
| if (iterator.hasNext() && ensureSingletonProvider()) { |
| throw new ServiceConfigurationError( |
| "More than on LoggerFinder implementation"); |
| } |
| } else { |
| result = loadDefaultImplementation(); |
| } |
| } catch (Error | RuntimeException x) { |
| // next caller will get the plain default impl (not linked |
| // to java.util.logging) |
| service = result = new DefaultLoggerFinder(); |
| ErrorPolicy errorPolicy = configurationErrorPolicy(); |
| if (errorPolicy == ErrorPolicy.ERROR) { |
| // rethrow any exception as a ServiceConfigurationError. |
| if (x instanceof Error) { |
| throw x; |
| } else { |
| throw new ServiceConfigurationError( |
| "Failed to instantiate LoggerFinder provider; Using default.", x); |
| } |
| } else if (errorPolicy != ErrorPolicy.QUIET) { |
| // if QUIET just silently use the plain default impl |
| // otherwise, log a warning, possibly adding the exception |
| // stack trace (if DEBUG is specified). |
| SimpleConsoleLogger logger = |
| new SimpleConsoleLogger("jdk.internal.logger", false); |
| logger.log(System.Logger.Level.WARNING, |
| "Failed to instantiate LoggerFinder provider; Using default."); |
| if (errorPolicy == ErrorPolicy.DEBUG) { |
| logger.log(System.Logger.Level.WARNING, |
| "Exception raised trying to instantiate LoggerFinder", x); |
| } |
| } |
| } |
| return result; |
| } |
| |
| private static System.LoggerFinder loadDefaultImplementation() { |
| final SecurityManager sm = System.getSecurityManager(); |
| final Iterator<DefaultLoggerFinder> iterator; |
| if (sm == null) { |
| iterator = ServiceLoader.loadInstalled(DefaultLoggerFinder.class).iterator(); |
| } else { |
| // We use limited do privileged here - the minimum set of |
| // permissions required to 'see' the META-INF/services resources |
| // seems to be CLASSLOADER_PERMISSION and READ_PERMISSION. |
| // Note that do privileged is required because |
| // otherwise the SecurityManager will prevent the ServiceLoader |
| // from seeing the installed provider. |
| PrivilegedAction<Iterator<DefaultLoggerFinder>> pa = () -> |
| ServiceLoader.loadInstalled(DefaultLoggerFinder.class).iterator(); |
| iterator = AccessController.doPrivileged(pa, null, |
| LOGGERFINDER_PERMISSION, CLASSLOADER_PERMISSION, |
| READ_PERMISSION); |
| } |
| DefaultLoggerFinder result = null; |
| try { |
| // Iterator iterates with the access control context stored |
| // at ServiceLoader creation time. |
| if (iterator.hasNext()) { |
| result = iterator.next(); |
| } |
| } catch (RuntimeException x) { |
| throw new ServiceConfigurationError( |
| "Failed to instantiate default LoggerFinder", x); |
| } |
| if (result == null) { |
| result = new DefaultLoggerFinder(); |
| } |
| return result; |
| } |
| |
| public static System.LoggerFinder getLoggerFinder() { |
| final SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) { |
| sm.checkPermission(LOGGERFINDER_PERMISSION); |
| } |
| return service(); |
| } |
| |
| } |