|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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; |
|
|
|
|
|
|
|
*/ |
|
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. |
|
|
|
private static enum ErrorPolicy { ERROR, WARNING, DEBUG, QUIET }; |
|
|
|
|
|
private LoggerFinderLoader() { |
|
throw new InternalError("LoggerFinderLoader cannot be instantiated"); |
|
} |
|
|
|
|
|
|
|
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 |
|
|
|
BootstrapLogger.redirectTemporaryLoggers(); |
|
return service; |
|
} |
|
|
|
|
|
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. |
|
|
|
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 |
|
|
|
private static System.LoggerFinder loadLoggerFinder() { |
|
System.LoggerFinder result; |
|
try { |
|
// Iterator iterates with the access control context stored |
|
|
|
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 |
|
|
|
service = result = new DefaultLoggerFinder(); |
|
ErrorPolicy errorPolicy = configurationErrorPolicy(); |
|
if (errorPolicy == ErrorPolicy.ERROR) { |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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(); |
|
} |
|
|
|
} |