8005615: Java Logger fails to load tomcat logger implementation (JULI)

Reviewed-by: alanb, ahgross
This commit is contained in:
Mandy Chung 2013-01-10 19:43:36 -08:00
parent be64e9b087
commit 3243aaf47a
5 changed files with 513 additions and 140 deletions

View File

@ -158,7 +158,7 @@ public class LogManager {
// LoggerContext for system loggers and user loggers
private final LoggerContext systemContext = new SystemLoggerContext();
private final LoggerContext userContext = new UserLoggerContext();
private final LoggerContext userContext = new LoggerContext();
private Logger rootLogger;
// Have we done the primordial reading of the configuration file?
@ -196,13 +196,13 @@ public class LogManager {
// Create and retain Logger for the root of the namespace.
manager.rootLogger = manager.new RootLogger();
manager.systemContext.addLogger(manager.rootLogger);
manager.userContext.addLogger(manager.rootLogger);
manager.addLogger(manager.rootLogger);
manager.systemContext.addLocalLogger(manager.rootLogger);
// Adding the global Logger. Doing so in the Logger.<clinit>
// would deadlock with the LogManager.<clinit>.
Logger.getGlobal().setLogManager(manager);
manager.systemContext.addLogger(Logger.getGlobal());
Logger.global.setLogManager(manager);
manager.addLogger(Logger.global);
// We don't call readConfiguration() here, as we may be running
// very early in the JVM startup sequence. Instead readConfiguration
@ -373,7 +373,7 @@ public class LogManager {
// Returns the LoggerContext for the user code (i.e. application or AppContext).
// Loggers are isolated from each AppContext.
LoggerContext getUserContext() {
private LoggerContext getUserContext() {
LoggerContext context = null;
SecurityManager sm = System.getSecurityManager();
@ -394,8 +394,8 @@ public class LogManager {
if (javaAwtAccess.isMainAppContext()) {
context = userContext;
} else {
context = new UserLoggerContext();
context.addLogger(manager.rootLogger);
context = new LoggerContext();
context.addLocalLogger(manager.rootLogger);
}
javaAwtAccess.put(ecx, LoggerContext.class, context);
}
@ -406,10 +406,6 @@ public class LogManager {
return context;
}
LoggerContext getSystemContext() {
return systemContext;
}
private List<LoggerContext> contexts() {
List<LoggerContext> cxs = new ArrayList<>();
cxs.add(systemContext);
@ -417,6 +413,58 @@ public class LogManager {
return cxs;
}
// Find or create a specified logger instance. If a logger has
// already been created with the given name it is returned.
// Otherwise a new logger instance is created and registered
// in the LogManager global namespace.
// This method will always return a non-null Logger object.
// Synchronization is not required here. All synchronization for
// adding a new Logger object is handled by addLogger().
//
// This method must delegate to the LogManager implementation to
// add a new Logger or return the one that has been added previously
// as a LogManager subclass may override the addLogger, getLogger,
// readConfiguration, and other methods.
Logger demandLogger(String name, String resourceBundleName) {
Logger result = getLogger(name);
if (result == null) {
// only allocate the new logger once
Logger newLogger = new Logger(name, resourceBundleName);
do {
if (addLogger(newLogger)) {
// We successfully added the new Logger that we
// created above so return it without refetching.
return newLogger;
}
// We didn't add the new Logger that we created above
// because another thread added a Logger with the same
// name after our null check above and before our call
// to addLogger(). We have to refetch the Logger because
// addLogger() returns a boolean instead of the Logger
// reference itself. However, if the thread that created
// the other Logger is not holding a strong reference to
// the other Logger, then it is possible for the other
// Logger to be GC'ed after we saw it in addLogger() and
// before we can refetch it. If it has been GC'ed then
// we'll just loop around and try again.
result = getLogger(name);
} while (result == null);
}
return result;
}
Logger demandSystemLogger(String name, String resourceBundleName) {
return systemContext.demandLogger(name, resourceBundleName);
}
// LoggerContext maintains the logger namespace per context.
// The default LogManager implementation has one system context and user
// context. The system context is used to maintain the namespace for
// all system loggers and is queried by the system code. If a system logger
// doesn't exist in the user context, it'll also be added to the user context.
// The user context is queried by the user code and all other loggers are
// added in the user context.
static class LoggerContext {
// Table of named Loggers that maps names to Loggers.
private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
@ -427,6 +475,12 @@ public class LogManager {
this.root = new LogNode(null, this);
}
Logger demandLogger(String name, String resourceBundleName) {
// a LogManager subclass may have its own implementation to add and
// get a Logger. So delegate to the LogManager to do the work.
return manager.demandLogger(name, resourceBundleName);
}
synchronized Logger findLogger(String name) {
LoggerWeakRef ref = namedLoggers.get(name);
if (ref == null) {
@ -441,7 +495,9 @@ public class LogManager {
return logger;
}
synchronized boolean addLogger(Logger logger) {
// Add a logger to this context. This method will only set its level
// and process parent loggers. It doesn't set its handlers.
synchronized boolean addLocalLogger(Logger logger) {
final String name = logger.getName();
if (name == null) {
throw new NullPointerException();
@ -474,9 +530,9 @@ public class LogManager {
doSetLevel(logger, level);
}
// Do we have a per logger handler too?
// Note: this will add a 200ms penalty
manager.loadLoggerHandlers(logger, name, name + ".handlers");
// instantiation of the handler is done in the LogManager.addLogger
// implementation as a handler class may be only visible to LogManager
// subclass for the custom log manager case
processParentHandlers(logger, name);
// Find the new node and its parent.
@ -513,50 +569,21 @@ public class LogManager {
return namedLoggers.keys();
}
Logger demandLogger(String name) {
return demandLogger(name, null);
}
// Find or create a specified logger instance. If a logger has
// already been created with the given name it is returned.
// Otherwise a new logger instance is created and registered
// in the LogManager global namespace.
// This method will always return a non-null Logger object.
// Synchronization is not required here. All synchronization for
// adding a new Logger object is handled by addLogger().
Logger demandLogger(String name, String resourceBundleName) {
Logger result = findLogger(name);
if (result == null) {
// only allocate the new logger once
Logger newLogger = new Logger(name, resourceBundleName);
do {
if (addLogger(newLogger)) {
// We successfully added the new Logger that we
// created above so return it without refetching.
return newLogger;
}
// We didn't add the new Logger that we created above
// because another thread added a Logger with the same
// name after our null check above and before our call
// to addLogger(). We have to refetch the Logger because
// addLogger() returns a boolean instead of the Logger
// reference itself. However, if the thread that created
// the other Logger is not holding a strong reference to
// the other Logger, then it is possible for the other
// Logger to be GC'ed after we saw it in addLogger() and
// before we can refetch it. If it has been GC'ed then
// we'll just loop around and try again.
result = findLogger(name);
} while (result == null);
}
return result;
}
// If logger.getUseParentHandlers() returns 'true' and any of the logger's
// parents have levels or handlers defined, make sure they are instantiated.
private void processParentHandlers(Logger logger, String name) {
private void processParentHandlers(final Logger logger, final String name) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
if (logger != manager.rootLogger) {
boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true);
if (!useParent) {
logger.setUseParentHandlers(false);
}
}
return null;
}
});
int ix = 1;
for (;;) {
int ix2 = name.indexOf(".", ix);
@ -564,12 +591,11 @@ public class LogManager {
break;
}
String pname = name.substring(0, ix2);
if (manager.getProperty(pname + ".level") != null ||
manager.getProperty(pname + ".handlers") != null) {
// This pname has a level/handlers definition.
// Make sure it exists.
demandLogger(pname);
demandLogger(pname, null);
}
ix = ix2+1;
}
@ -607,53 +633,51 @@ public class LogManager {
}
static class SystemLoggerContext extends LoggerContext {
// Default resource bundle for all system loggers
Logger demandLogger(String name) {
// default to use the system logger's resource bundle
return super.demandLogger(name, Logger.SYSTEM_LOGGER_RB_NAME);
}
}
static class UserLoggerContext extends LoggerContext {
/**
* Returns a Logger of the given name if there is one registered
* in this context. Otherwise, it will return the one registered
* in the system context if there is one. The returned Logger
* instance may be initialized with a different resourceBundleName.
* If no such logger exists, a new Logger instance will be created
* and registered in this context.
*/
// Add a system logger in the system context's namespace as well as
// in the LogManager's namespace if not exist so that there is only
// one single logger of the given name. System loggers are visible
// to applications unless a logger of the same name has been added.
Logger demandLogger(String name, String resourceBundleName) {
Logger result = findLogger(name);
if (result == null) {
// use the system logger if exists; or allocate a new logger.
// The system logger is added to the app logger context so that
// any child logger created in the app logger context can have
// a system logger as its parent if already exist.
Logger logger = manager.systemContext.findLogger(name);
Logger newLogger =
logger != null ? logger : new Logger(name, resourceBundleName);
// only allocate the new system logger once
Logger newLogger = new Logger(name, resourceBundleName);
do {
if (addLogger(newLogger)) {
if (addLocalLogger(newLogger)) {
// We successfully added the new Logger that we
// created above so return it without refetching.
return newLogger;
result = newLogger;
} else {
// We didn't add the new Logger that we created above
// because another thread added a Logger with the same
// name after our null check above and before our call
// to addLogger(). We have to refetch the Logger because
// addLogger() returns a boolean instead of the Logger
// reference itself. However, if the thread that created
// the other Logger is not holding a strong reference to
// the other Logger, then it is possible for the other
// Logger to be GC'ed after we saw it in addLogger() and
// before we can refetch it. If it has been GC'ed then
// we'll just loop around and try again.
result = findLogger(name);
}
// We didn't add the new Logger that we created above
// because another thread added a Logger with the same
// name after our null check above and before our call
// to addLogger(). We have to refetch the Logger because
// addLogger() returns a boolean instead of the Logger
// reference itself. However, if the thread that created
// the other Logger is not holding a strong reference to
// the other Logger, then it is possible for the other
// Logger to be GC'ed after we saw it in addLogger() and
// before we can refetch it. If it has been GC'ed then
// we'll just loop around and try again.
result = findLogger(name);
} while (result == null);
}
// Add the system logger to the LogManager's namespace if not exists
// The LogManager will set its handlers via the LogManager.addLogger method.
if (!manager.addLogger(result) && result.getHandlers().length == 0) {
// if logger already exists but handlers not set
final Logger l = manager.getLogger(name);
final Logger logger = result;
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
for (Handler hdl : l.getHandlers()) {
logger.addHandler(hdl);
}
return null;
}
});
}
return result;
}
}
@ -663,22 +687,16 @@ public class LogManager {
// be made based on the logging configuration, which can
// only be modified by trusted code.
private void loadLoggerHandlers(final Logger logger, final String name,
final String handlersPropertyName) {
final String handlersPropertyName)
{
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
if (logger != rootLogger) {
boolean useParent = getBooleanProperty(name + ".useParentHandlers", true);
if (!useParent) {
logger.setUseParentHandlers(false);
}
}
String names[] = parseClassNames(handlersPropertyName);
for (int i = 0; i < names.length; i++) {
String word = names[i];
try {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
Handler hdl = (Handler) clz.newInstance();
Handler hdl = (Handler) clz.newInstance();
// Check if there is a property defining the
// this handler's level.
String levs = getProperty(word + ".level");
@ -700,7 +718,8 @@ public class LogManager {
}
}
return null;
}});
}
});
}
@ -839,13 +858,17 @@ public class LogManager {
if (name == null) {
throw new NullPointerException();
}
if (systemContext.findLogger(name) != null) {
LoggerContext cx = getUserContext();
if (cx.addLocalLogger(logger)) {
// Do we have a per logger handler too?
// Note: this will add a 200ms penalty
loadLoggerHandlers(logger, name, name + ".handlers");
return true;
} else {
return false;
}
return getUserContext().addLogger(logger);
}
// Private method to set a level on a logger.
// If necessary, we raise privilege before doing the call.
private static void doSetLevel(final Logger logger, final Level level) {
@ -864,8 +887,6 @@ public class LogManager {
}});
}
// Private method to set a parent on a logger.
// If necessary, we raise privilege before doing the setParent call.
private static void doSetParent(final Logger logger, final Logger parent) {
@ -900,15 +921,7 @@ public class LogManager {
* @return matching logger or null if none is found
*/
public Logger getLogger(String name) {
// return the first logger added
//
// once a system logger is added in the system context, no one can
// adds a logger with the same name in the global context
// (see LogManager.addLogger). So if there is a logger in the global
// context with the same name as one in the system context, it must be
// added before the system logger was created.
Logger logger = getUserContext().findLogger(name);
return logger != null ? logger : systemContext.findLogger(name);
return getUserContext().findLogger(name);
}
/**
@ -928,10 +941,7 @@ public class LogManager {
* @return enumeration of logger name strings
*/
public Enumeration<String> getLoggerNames() {
// only return unique names
Set<String> names = new HashSet<>(Collections.list(systemContext.getLoggerNames()));
names.addAll(Collections.list(getUserContext().getLoggerNames()));
return Collections.enumeration(names);
return getUserContext().getLoggerNames();
}
/**
@ -1329,7 +1339,6 @@ public class LogManager {
// that we only instantiate the global handlers when they
// are first needed.
private class RootLogger extends Logger {
private RootLogger() {
super("", null);
setLevel(defaultLevel);

View File

@ -31,7 +31,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.security.*;
import java.lang.ref.WeakReference;
import java.util.function.Supplier;
import java.util.logging.LogManager.LoggerContext;
/**
* A Logger object is used to log messages for a specific
@ -321,18 +320,32 @@ public class Logger {
//
// As an interim solution, if the immediate caller whose caller loader is
// null, we assume it's a system logger and add it to the system context.
private static LoggerContext getLoggerContext() {
// These system loggers only set the resource bundle to the given
// resource bundle name (rather than the default system resource bundle).
private static class SystemLoggerHelper {
static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck");
private static boolean getBooleanProperty(final String key) {
String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty(key);
}
});
return Boolean.valueOf(s);
}
}
private static Logger demandLogger(String name, String resourceBundleName) {
LogManager manager = LogManager.getLogManager();
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// 0: Reflection 1: Logger.getLoggerContext 2: Logger.getLogger 3: caller
if (sm != null && !SystemLoggerHelper.disableCallerCheck) {
// 0: Reflection 1: Logger.demandLogger 2: Logger.getLogger 3: caller
final int SKIP_FRAMES = 3;
Class<?> caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES);
if (caller.getClassLoader() == null) {
return manager.getSystemContext();
return manager.demandSystemLogger(name, resourceBundleName);
}
}
return manager.getUserContext();
return manager.demandLogger(name, resourceBundleName);
}
/**
@ -376,8 +389,7 @@ public class Logger {
// would throw an IllegalArgumentException in the second call
// because the wrapper would result in an attempt to replace
// the existing "resourceBundleForFoo" with null.
LoggerContext context = getLoggerContext();
return context.demandLogger(name);
return demandLogger(name, null);
}
/**
@ -424,8 +436,7 @@ public class Logger {
// Synchronization is not required here. All synchronization for
// adding a new Logger object is handled by LogManager.addLogger().
public static Logger getLogger(String name, String resourceBundleName) {
LoggerContext context = getLoggerContext();
Logger result = context.demandLogger(name, resourceBundleName);
Logger result = demandLogger(name, resourceBundleName);
// MissingResourceException or IllegalArgumentException can be
// thrown by setupResourceInfo().
@ -438,11 +449,10 @@ public class Logger {
// i.e. caller of sun.util.logging.PlatformLogger.getLogger
static Logger getPlatformLogger(String name) {
LogManager manager = LogManager.getLogManager();
LoggerContext context = manager.getSystemContext();
// all loggers in the system context will default to
// the system logger's resource bundle
Logger result = context.demandLogger(name);
Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME);
return result;
}
@ -1588,7 +1598,8 @@ public class Logger {
public ResourceBundle run() {
try {
return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME,
locale);
locale,
ClassLoader.getSystemClassLoader());
} catch (MissingResourceException e) {
throw new InternalError(e.toString());
}

View File

@ -0,0 +1,177 @@
/*
* Copyright (c) 2013, 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.
*
* 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.
*/
import java.io.*;
import java.util.*;
import java.util.logging.*;
/*
* Custom LogManager implementation to verify that the implementation delegates
* to the LogManager subclass to register both system logger and user logger.
*
* The LogManager implementation is the one configuring the logger's property
* such as level, handler, etc.
*/
public class CustomLogManager extends LogManager {
static LogManager INSTANCE;
Map<String,Logger> namedLoggers = new HashMap<>();
Properties props = initConfig();
public CustomLogManager() {
if (INSTANCE != null) {
throw new RuntimeException("CustomLogManager already created");
}
INSTANCE = this;
}
public synchronized boolean addLogger(Logger logger) {
String name = logger.getName();
if (namedLoggers.containsKey(name)) {
return false;
}
namedLoggers.put(name, logger);
// set level
if (props.get(name + ".level") != null) {
logger.setLevel(Level.parse(props.getProperty(name + ".level")));
}
// add handlers
if (props.get(name + ".handlers") != null && logger.getHandlers().length == 0) {
logger.addHandler(new CustomHandler());
}
// add parent loggers
int ix = 1;
for (;;) {
int ix2 = name.indexOf(".", ix);
if (ix2 < 0) {
break;
}
String pname = name.substring(0, ix2);
if (props.get(pname + ".level") != null ||
props.get(pname + ".handlers") != null) {
// This pname has a level/handlers definition.
// Make sure it exists.
//
// The test doesn't set the parent for simplicity.
if (!namedLoggers.containsKey(pname)) {
Logger.getLogger(pname);
}
}
ix = ix2 + 1;
}
return true;
}
public synchronized Logger getLogger(String name) {
return namedLoggers.get(name);
}
public synchronized Enumeration<String> getLoggerNames() {
return Collections.enumeration(namedLoggers.keySet());
}
public String getProperty(String name) {
return props.getProperty(name);
}
public void readConfiguration() {
// do nothing
}
public void readConfiguration(InputStream ins) {
// do nothing
}
private Properties initConfig() {
Properties props = new Properties();
props.put(".level", "CONFIG");
props.put("CustomLogManagerTest.level", "WARNING");
props.put("CustomLogManagerTest.handlers", "CustomLogManager$CustomHandler");
props.put("SimpleLogManager.level", "INFO");
props.put("SimpleLogManager.handlers", "CustomLogManager$CustomHandler");
props.put("CustomLogManager$CustomHandler.level", "WARNING");
props.put(".handlers", "CustomLogManager$CustomHandler");
props.put("org.foo.bar.level", "SEVERE");
props.put("org.foo.handlers", "CustomLogManager$CustomHandler");
props.put("org.openjdk.level", "SEVERE");
props.put("org.openjdk.handlers", "CustomLogManager$CustomHandler");
props.put("org.openjdk.core.level", "INFO");
return props;
}
public static void checkLogger(String name) {
checkLogger(name, null);
}
public static void checkLogger(String name, String resourceBundleName) {
Logger logger = INSTANCE.getLogger(name);
if (logger == null) {
throw new RuntimeException("Logger \"" + name + "\" not exist");
}
System.out.format("Logger \"%s\" level=%s handlers=%s resourcebundle=%s%n",
name, logger.getLevel(),
Arrays.toString(logger.getHandlers()),
logger.getResourceBundleName());
String rb = logger.getResourceBundleName();
if (rb != resourceBundleName && (rb == null || rb.equals(resourceBundleName))) {
throw new RuntimeException("Logger \"" + name +
"\" unexpected resource bundle: " + rb);
}
String value = INSTANCE.getProperty(name + ".level");
String level = logger.getLevel() != null ? logger.getLevel().getName() : null;
if (level != value && (level == null || level.equals(value))) {
throw new RuntimeException("Logger \"" + name + "\" unexpected level: " + level);
}
Handler[] handlers = logger.getHandlers();
String hdl = INSTANCE.getProperty(name + ".handlers");
if ((hdl == null && handlers.length != 0) ||
(hdl != null && handlers.length != 1)) {
throw new RuntimeException("Logger \"" + name + "\" unexpected handler: " +
Arrays.toString(handlers));
}
checkParents(name);
}
private static void checkParents(String name) {
int ix = 1;
for (;;) {
int ix2 = name.indexOf(".", ix);
if (ix2 < 0) {
break;
}
String pname = name.substring(0, ix2);
if (INSTANCE.getProperty(pname + ".level") != null ||
INSTANCE.getProperty(pname + ".handlers") != null) {
// This pname has a level/handlers definition.
// Make sure it exists.
checkLogger(pname);
}
ix = ix2 + 1;
}
}
// only CustomLogManager can create an instance of CustomHandler
private class CustomHandler extends StreamHandler {
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2013, 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.
*
* 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.
*/
import java.io.*;
import java.util.*;
import java.util.logging.*;
import sun.util.logging.PlatformLogger;
/*
* @test
* @bug 8005615
* @summary Add loggers to custom log manager
*
* @compile -XDignore.symbol.file CustomLogManagerTest.java CustomLogManager.java
* @run main/othervm -Djava.util.logging.manager=CustomLogManager CustomLogManagerTest
*/
public class CustomLogManagerTest {
private static final String RESOURCE_BUNDLE = "sun.util.logging.resources.logging";
public static void main(String[] args) {
String mgr = System.getProperty("java.util.logging.manager");
if (!mgr.equals("CustomLogManager")) {
throw new RuntimeException("java.util.logging.manager not set");
}
Logger.getLogger(CustomLogManagerTest.class.getName());
Logger.getLogger("org.foo.Foo");
Logger.getLogger("org.foo.bar.Foo", RESOURCE_BUNDLE);
// platform logger will be set with the default system resource bundle
PlatformLogger.getLogger("org.openjdk.core.logger");
if (LogManager.getLogManager() != CustomLogManager.INSTANCE) {
throw new RuntimeException(LogManager.getLogManager() + " not CustomLogManager");
}
CustomLogManager.checkLogger(CustomLogManagerTest.class.getName());
CustomLogManager.checkLogger("org.foo.Foo");
CustomLogManager.checkLogger("org.foo.bar.Foo", RESOURCE_BUNDLE);
CustomLogManager.checkLogger(Logger.GLOBAL_LOGGER_NAME);
CustomLogManager.checkLogger("");
CustomLogManager.checkLogger("org.openjdk.core.logger", RESOURCE_BUNDLE);
}
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2013, 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.
*
* 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.
*/
import java.util.*;
import java.util.logging.*;
import sun.util.logging.PlatformLogger;
/*
* @test
* @bug 8005615
* @summary A LogManager subclass overrides its own implementation of named
* logger (see the subclassing information in the Logger class specification)
*
* @compile -XDignore.symbol.file CustomLogManager.java SimpleLogManager.java
* @run main/othervm -Djava.util.logging.manager=SimpleLogManager SimpleLogManager
*/
public class SimpleLogManager extends CustomLogManager {
public static void main(String[] args) {
String classname = System.getProperty("java.util.logging.manager");
if (!classname.equals("SimpleLogManager")) {
throw new RuntimeException("java.util.logging.manager not set");
}
Logger logger = Logger.getLogger(SimpleLogManager.class.getName());
Logger.getLogger("org.foo.bar.Foo");
// a platform logger used by the system code is just a Logger instance.
PlatformLogger.getLogger("org.openjdk.core.logger");
LogManager mgr = LogManager.getLogManager();
if (mgr != CustomLogManager.INSTANCE || !(mgr instanceof SimpleLogManager)) {
throw new RuntimeException(LogManager.getLogManager() + " not SimpleLogManager");
}
checkCustomLogger(SimpleLogManager.class.getName(), null);
checkCustomLogger("org.foo.bar.Foo", null);
checkCustomLogger("org.openjdk.core.logger", "sun.util.logging.resources.logging");
// ## The LogManager.demandLogger method does not handle custom log manager
// ## that overrides the getLogger method to return a custom logger
// ## (see the test case in 8005640). Logger.getLogger may return
// ## a Logger instance but LogManager overrides it with a custom Logger
// ## instance like this case.
//
// However, the specification of LogManager and Logger subclassing is
// not clear whether this is supported or not. The following check
// just captures the current behavior.
if (logger instanceof CustomLogger) {
throw new RuntimeException(logger + " not CustomLogger");
}
}
private static void checkCustomLogger(String name, String resourceBundleName) {
CustomLogManager.checkLogger(name, resourceBundleName);
Logger logger1 = Logger.getLogger(name);
Logger logger2 = LogManager.getLogManager().getLogger(name);
if (logger1 != logger2) {
throw new RuntimeException(logger1 + " != " + logger2);
}
if (!(logger1 instanceof CustomLogger)) {
throw new RuntimeException(logger1 + " not CustomLogger");
}
}
/*
* This SimpleLogManager overrides the addLogger method to replace
* the given logger with a custom logger.
*
* It's unclear what the recommended way to use custom logger is.
* A LogManager subclass might override the getLogger method to return
* a custom Logger and create a new custom logger if not exist so that
* Logger.getLogger() can return a custom Logger instance but that violates
* the LogManager.getLogger() spec which should return null if not found.
*/
public synchronized boolean addLogger(Logger logger) {
String name = logger.getName();
if (namedLoggers.containsKey(name)) {
return false;
}
CustomLogger newLogger = new CustomLogger(logger);
super.addLogger(newLogger);
return true;
}
public class CustomLogger extends Logger {
CustomLogger(Logger logger) {
super(logger.getName(), logger.getResourceBundleName());
}
CustomLogger(String name) {
super(name, null);
}
}
}